Build1 publisher3 min readPublished
Eleven bugs, one HStack: what a five-minute XXXL screenshot pass found that code review didn't
A developer set Dynamic Type to the largest size, screenshotted every screen, and surfaced the same layout defect eleven times. In Japanese it fails much earlier than in English.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction
What happened
- A developer cleaning up the UI on a side-project iOS app set Dynamic Type to XXXL and screenshotted every screen.
- The pass found eleven problems, all with the same cause.
- Reading the code had turned up nothing; the screenshots showed problems immediately.
- The author's stated conclusion: a parent that pins things side by side multiplied by text that grows is not a bug but a pattern.
- Nearly all eleven instances were an HStack containing an Image with a fixed 44pt width frame, a Text label, a Spacer, and a Text value pinned to the right.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
A developer cleaning up a side-project iOS app did one thing: set Dynamic Type to XXXL and screenshot every screen [1]. Reading the code had turned up nothing; the screenshots produced findings immediately, eleven of them, all with the same cause [2][3]. The cause is worth stating as a pattern rather than an incident: a parent that pins things side by side, multiplied by text that grows, is a structural defect [4]. Nearly all eleven instances were the same row: an HStack holding an icon with a fixed 44pt frame, a label, a Spacer, and a value pinned to the trailing edge [5]. The icon and the trailing value claim their width first, so the label column is left with a few characters [6]. That is where language decides how bad it looks. English wraps at word boundaries and, failing that, truncates with an ellipsis, which is unreadable but legibly broken [7]. Under enough pressure it breaks mid-word anyway; the author's actual output was "Paire / d / Macs" [8]. Japanese has no such boundary rule, so it can break between almost any two characters, and a column squeezed to one character wide stacks one character per line downward, a state Japanese reaches far earlier than English [9]. Same layout, two failure modes. The fix was to let rows carrying a value drop that value to the line below, while affordances such as chevrons and toggles stay on the right [10]. Because the row component was shared across the whole settings tree, one change repaired the entire settings screen, which is the same fact read the other way: one decision inside a shared component was breaking eleven screens [11]. The instructive part is the fix that misfired. Using ViewThatFits to swap in a stacked layout broke the standard text size [12]. ViewThatFits chooses on each child's ideal width, and a title that wraps reports its full unwrapped length as its ideal width, so the side-by-side candidate was judged not to fit and the badge dropped below the title at normal settings [13]. The author says he could not have reasoned his way there and found it by screenshotting the standard size [14]. His resulting split: ViewThatFits when every child is short with an intrinsic width, an explicit isAccessibilitySize branch when one child is a sentence that wraps [15]. He also reversed his own classification of a .menu Picker as pin-right after an audit-log screenshot showed the Japanese filter label shattered across lines [16], settling on a rule that only controls changing state in place stay pinned right, while anything that merely opens something may take the full row [17]. Two process findings matter more than the SwiftUI details. The UI-test env var applied dynamicTypeSize to the root view but did not propagate into a .sheet's environment, so the paywall and setup guide had never once been rendered at the largest size; green tests meant the tests passed, not that the modals were checked [18]. That is now driven from the system side with simctl content_size [19]. And after fixing six, the author declared the pattern converged; four more turned up on screens he had not looked at [20], and he only called it done after sweeping the QR scanner, host-add and pairing flows in Japanese at XXXL for zero new findings [21]. Count screens inspected, not bugs fixed [22]. The write-up itself enumerates ten before landing on eleven [29]. The adjacent sweep found the sibling defect: "1 items need attention" led to a string audit where zero of 38 English strings with a quantity placeholder had plural variants [23], including "1 days free" on the paywall and a share-sheet body that leaves the device [24]. Thirteen keys got variants, leaving 25 untouched, some deliberately because the number does not agree with the noun [25][28].