ADR-0088: Home statistics reflow by measured token; section actions reserve the FAB column
- Status: Accepted
- Date: 2026-11-03
- Related: ADR-0009, ADR-0043, ADR-0053, ADR-0062, ADR-0069, ADR-0079, ADR-0084
Context
W10 evidence at 411 dp / 200 % text (#406) showed three Home statistic cells
that had returned to a fixed three-way weight split. Each cell was narrower than
the words and formatted amounts it held, so MERCHANTS broke mid-word,
RM 1,500.00 broke inside the digits, and the recent section's View all
action sat beneath the shell's floating add button. The same source also let a
section action squeeze or wrap unpredictably whenever the title and action did
not fit together.
The stats already have a measured grid contract (ADR-0043), and the shell owns
the single FAB and its clearance (ShellMetrics). This ADR restores the
measured behaviour and gives the section-header action a safe relationship with
that one FAB.
Decision
Home statistics choose a column count from measured words, not from the
viewport alone. For each label and formatted value, measure the widest
space-delimited token with the active AppTextRole typography and the current
font scale. Prefer the familiar three equal columns; fall back to two, then one,
when a cell would be narrower than that token. Every cell keeps the full value
and the same semantic order. Labels wrap only between words, and monetary tokens
(+RM, 1,500.00) stay whole at supported widths and scales; a token wider
than the whole card still wraps inside that one full-width cell with every
character retained. Values are never shrunk, abbreviated or hidden.
The decision function is pure and JVM-tested, while HomeHeroCardTest covers
the rendered layouts at 320/411 dp and 100/150/200 % in light and dark.
A section action moves below its title rather than sharing an impossible
row. SectionHeader measures the title and trailing composable once through
their intrinsic widths. When both cannot keep their text in the available row it
stacks the action under the title, start-aligned, instead of squeezing or
wrapping either. Home passes the shell FAB's end column as the inline trailing
clearance, so even when the action stays inline it can never be covered by the
floating add button in either layout direction. The clearance is a named
ShellMetrics value derived from the FAB size; it is not a per-screen literal.
The one-FAB policy is unchanged.
Consequences
At large text or narrow widths the hero grows vertically and Home scrolls, which is the accepted cost of keeping every exact figure readable. At ordinary text on a 411 dp phone the three-column row and the inline View all are unchanged; on a 320 dp phone or at large text the action stacks under its title, and the inline form always ends before the FAB column instead of under it. Section headers on other destinations adopt the measured stacking behaviour but pass no FAB clearance, because they do not host the add action. Long minor units, formatting, drafts, lock state and route contracts are untouched.
Verification
HomeStatLayoutTest covers the column boundaries; HomeHeroCardTest covers
glyph, wrapping and containment at 320/411 dp, 100/150/200 % and light/dark,
including large multi-group amounts; HomeLargeTextRegressionTest renders the
real shell at 411 x 914 / 200 %, 320 x 568 / 200 %, 411 x 500 / 100 % (inline
and RTL), 150 %, dark dynamic colour, empty and revoked-capture states, asserts
whole tokens, checks the action and FAB stay inside the simulated/physical
viewport, performs a real touch click on the 48 dp View all target and
navigates through the month-scoped Activity route and Back; SectionHeaderTest
covers inline clearance, inline RTL mirroring and large-text stacking; the shell
chrome test pins the named action clearance. The fixed-size cases scale the
simulated density so the logical 411/320 dp viewport fits the physical CI
window, then assert the simulated viewport maps inside the real px bounds while
the root keeps its requested logical size; this preserves the 411 audit locally
and the 320 CI lane without falling back to unclipped roots. Manual API 26
captures and the W12 evidence archive are review artifacts for this run and are
not committed binaries. TalkBack traversal and cutout/foldable evidence remain
manual scope; #407 is being fixed separately in W13. #393's tracker state
(closed at review time) must not be read as acceptance for those cases.