docs: the transcript's edges were three faults, and what the rig found

IRIS_TODO's 2026-09-07 top-edge entry closed with the root cause of
each, the six layer-1 test names, and what was suspected and turned out
not to be it -- no culling test compared a row's top against the
viewport's, and 03c6be8's header duplicate is untouched and still open.
The later report's "you shouldn't be able to scroll below the bottom (or
above top)" is ticked with why the clamp is a correction measured from
the layout walk rather than a clamp inside the scroll setter: nothing at
the moment of a scroll knows where the content ends.

RUST.md gains the same account in "Where things stand", plus the three
things this said about the new test rig -- layer 1 found all of it in
seconds and the emulator was not used; layer 2 is where the missing clip
is visible, with the command; and an assertion that reads the wrong
thing hides the bug it is for, which is how a list resting 1398px past
its own first row passed a test about stopping at that row.

Also the last of the six tests, the bottom end of the clamp
(`scrolling_past_the_last_row_settles_on_it`) -- the same rule at the
edge the top-edge work had no reason to touch.
This commit is contained in:
iris committed 2026-09-07 16:07:37 -04:00
1 parent e922b73d7a
commit 690161e5e9
3 files changed
+134 -5

No files matched your search

+54 -2
View File
@@ -43,6 +43,52 @@ gated on her verdict**, so this pass works the P0 defects and the pure
prerequisites in this order. Each item is ticked here by the agent that
closes it.
### The transcript's edges (2026-09-07, e922b73 + d507ae4)
Iris's two screenshots of the top edge -- rows drawn over the header in
one, a blank band in the other -- were **three** faults, and the rule
that fixes all three is the one the IRIS_TODO entry asked for: *a row is
drawn if any part of it overlaps the list's own box, and nothing outside
that box reaches the screen* (`List::intersects_viewport`). Neither
suspected cause was right, which is worth reading before trusting the
next suspicion in this file: there was no visible-range test comparing a
row's top against the viewport's, and `03c6be8`'s header duplicate is
untouched and still open.
What was actually wrong: **nothing clipped the list at all** (and it
could not be `.masked()`, because `Painter::set_mask` aborted whenever
an ancestor had a mask and the list's own rows use one -- so masks
nest now, `Mask::parent`, walked in the fragment stage); **the layout
walk drew every row between the anchor and the viewport**, which after
panning is however far you have panned, measured at 64 rows placed for
a 2012px viewport; and **the list could rest past its own first row**,
which is the blank band, and is also the first item of Iris's later
report the same day. Details and the six layer-1 test names are in
docs/IRIS_TODO.md's 2026-09-07 entry.
Three things this says about the rig, since the rig is new:
- **Layer 1 found all of it, in seconds.** The tests open the real
screen over the real fixture under a bench-app-shaped header
(`iris/transcript-fixture/tests/top_edge.rs`, `cargo test -p
transcript-fixture`, ~5s), and each was confirmed to fail on its own
subject and no other by breaking that subject on purpose. The
emulator was not used, and the phone will only be asked to confirm.
- **Layer 2 is where the clip is visible.** `iris/run-headless.sh phone
--phone --replay transcript-fixture/touch/flick-120hz.touch --shot
/tmp/p.png -- -p transcript-fixture`, run with `.masked()` removed,
draws the bottom row's text over the composer bar; with it, the same
flick clips cleanly at the bar. The window has no header, so the top
edge is the window edge there -- the header case is layer 1's.
- **An assertion that reads the wrong thing hides the bug it is for.**
`fling_toward_the_start_stops_at_the_first_row` asserted the first
row's top was `>= -0.5` while that row sat 1398px *below* a 600px
viewport with the screen blank: `extents` then held rows that were
not on screen, so the read was satisfied by the failure. `extents`
now holds only what is on screen -- which is what `key_at` always
claimed of it -- asserted at the end of every draw, and the test
checks both directions.
### APK size (2026-09-07)
Iris's question: the iris bench APK is about double the Compose bench APK
@@ -223,9 +269,10 @@ closes it.
- [x] Test rig, layers 1 and 2 ("Three test layers" below), landed 2026-09-07.
- [ ] Fling parity with Compose, and the phone's keyboard push-up, with
insets shown in the diagnostics overlay. Running, in a worktree.
- [ ] Rows at the transcript's top edge: culled too early in one state,
- [x] Rows at the transcript's top edge: culled too early in one state,
drawn through the header in the other (docs/IRIS_TODO.md, 2026-09-07).
First after the rig lands, using its layer-1 harness.
Done 2026-09-07, e922b73 + d507ae4; the root causes and the test names
are in that IRIS_TODO entry, and the short version is below.
- [ ] Phone logging through Dev Updater (Iris has no logcat; see
docs/TODO.md and the memory note): research how Dev Updater shows an
app's runtime log, design the smallest route (the app keeps its own
@@ -249,6 +296,11 @@ closes it.
2026-09-07)". A mask references a primitive already drawn
(rect SDF, texture or glyph alpha), chained and multiplied; `.masked()`
points at the widget's own primitives; hit-testing applies the shape.
**Chaining landed early**, 2026-09-07 (d507ae4): a mask carries the
mask it was set inside and the fragment stage walks that chain, so
nesting works and `Painter::set_mask` no longer aborts on it. Still
rectangles only -- the shape half, and the hit-testing half, are what
is left of this item.
- [ ] Compose app: the `Reversed range` crash in `ToolInput.highlighted`
(docs/TODO.md). Main branch, not rustify.