Repository navigation
Commit ceff9c3
committed
fix(contracts): refuse a band whose keys do not tile the width it claims
A split iPad keyboard docks both clusters at the bottom edge, and its surface container still
reports the whole screen width, so the docking and width rules passed and the band ran across the
middle of the screen — where the app content between the clusters is visible and tappable. The
container says where the platform thinks the keyboard is; only the keys say where its controls are,
so the band now measures whether the keys form one unbroken run of columns before trusting any of
it. A gap is not something the band can be built around: nothing in the tree says where either
cluster ends, so the geometry stays unmeasured and the tap fails open, as it does for a rotated
keyboard or a floating one.
Measured, not assumed. iPhone 17 Pro (26.2) reports a key row adjoining across 395 pt, iPad Pro
11-inch (M4) across 743.5 pt, and Gboard on Pixel 7 across 1070 px, none with a gap above a point,
so the allowance is for projection rounding rather than layout — and the reduced two-key keyboards
the table had been modelling now carry the measured row, which is what makes the new rule bite on a
modelled split cluster instead of on a reporting seam. The same pass measured a three-button
navigation bar on Android (126 px at 2274..2400 inside Gboard's reported region, which runs to the
physical display bottom) and a docked iPad keyboard stopping 3 pt short of its viewport bottom, both
now table rows.
The rule is blunt in both directions and the table pins both costs: a sparse layout such as the iOS
emoji panel reports corner keys over a wide container, does not tile, and reads undetermined, because
choosing which gaps are app content is exactly the invention that produced the split-keyboard bug; and
a projection reporting the container with no keys has nothing left to check, so the band is the
container's own claim — every captured iOS and Android keyboard so far reports its keys, so that shape
is the harness's rather than a captured one.
Cases that reach a band also owe their whole shape now: the frame the refusal and the disclosure
quote, and the control rects, which is where plane exclusion shows up. Previously the frame was
compared only on occluded verdicts and the control rects never, so a regression in plane exclusion or
in a clear verdict's band passed silently.
The measurement rules are each one named function now, and the two ancestry walks the module carried
— one asking whether a node belongs to the keyboard, one asking which nodes have keyboard nodes below
them — read the projection's parent links through one primitive.1 parent 1a14572 commit ceff9c3
3 files changed
Lines changed: 2585 additions & 283 deletions
File tree
- contracts/fixtures
- packages/contracts/src
0 commit comments