diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index f038819..c670d50 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -26,18 +26,14 @@ reference renders and the resize render are byte-identical across all of it, and the hundred-seed sweep passes. `/home/bob/repos/ai-app-2` is on `rustify`, worktree clean. -**The one thing waiting on the owner.** `tabs` at 1920x1200 is no longer -byte-identical to `upstream/main`: 1,283 pixels of 2.3M (0.06%), two -one-pixel-wide panel edges shifted by a pixel, at x=1056 and x=1337. `view`, -`minimal` and `text` are identical. Composing a position through the chain in -the shader associates the arithmetic differently from collapsing it on the CPU, -so a value that used to land exactly on an integer falls the other side of the -shader's `floor`. The CPU and the GPU still agree with each other -- both walk -the chain bottom-up -- so hit testing matches what is drawn; what changed is -only the comparison against the old code. Matching it exactly means composing -root-down in the shader, which needs the chain collected into an array first. -Byte-identical against `upstream/main` has been the bar for every slice, so -this is hers to accept or to spend a commit on. +**The `tabs` divergence does not reproduce, so nothing waits on the owner.** +Re-measured 2026-09-15 at `f61e893` against `upstream/main` built in its own +worktree: `tabs` at 1920x1200 is byte-identical, and so are a cold 900x1200 and +a resize from 1920x1200 down to it. Both sides render the same bytes twice, so +it is not a flaky shot. The earlier reading of 1,283 differing pixels at x=1056 +and x=1337 is withdrawn; it was taken before `02ff8c7` and `f61e893`, and a +target directory shared between the two checkouts is the trap the render +section already warns about. Byte-identical against `upstream/main` is met. Check for a review before starting anything, and read the newest `submitted_at` rather than the first result: @@ -102,6 +98,21 @@ Invariants, not history. Everything in `core/src/ui` rests on them. Marking descendants for redraw instead does not terminate: the mark escalates to that descendant's size reader, which re-places the child, which marks it again. Asking first and giving up the whole reuse adds no marks and stops. +- **A fixed pixel length keeps its pixel width through any chain.** Both edges + of such a part share their box's `rel`, and `within` is a function of that + `rel` alone, so the shader's `floor(rel * dim)` is the same for both edges + while the `px` parts still differ by exactly one. A hairline or a one-pixel + gap can therefore move by a pixel when a position falls the other side of the + `floor`; it cannot be widened or deleted by one. Only a length expressed as a + fraction can round away, and that was as true before the chain. Measured + 2026-09-15 with `examples/thin.rs` (untracked in the #18 worktree): sixteen + one-pixel lines and sixteen one-pixel gaps under four levels of span, padding + and `rest(3)/rest(7)/rest(5)`, rendered at six output sizes on + `upstream/main` and at `f61e893`. Every run is exactly one pixel on both, and + a line sits within one pixel of where the other revision put it. At 640x481 + the fixture is over-constrained -- the fixed pixels exceed the box -- and the + same three gaps vanish on both revisions, which is the span overflowing + rather than anything rounding. - **The walk stops where a length did not change.** A part of a box with no relative extent on an axis is a fixed length held as offsets from that box's start, and composing anything into it leaves no relative extent either -- so a @@ -374,6 +385,23 @@ Memory on the same rig at 2,000 rows: 108.6 MB on #18's head, 111.6 MB with both, and **132.0 MB before #16**, which grows 23 MB over the resizes where neither of the others grows at all. +**Re-measured at `f61e893`, which is the number to quote.** The same rig, the +same two worktrees each with its own target directory, 500 resize frames at 40 +rows, taken with `perf stat -e instructions:u` on the test binary: + +| | before #16 (`43ce8c7`) | #18 head (`f61e893`) | +| --- | --- | --- | +| instructions/frame, alternating | 56.1M | 15.3M | +| instructions/frame, never repeating | 56.1M | 15.5M | +| median frame | 5.32 ms | 1.29 ms | +| worst frame | 8.06 ms | 1.81 ms | +| RSS after 40 resizes, 2,000 rows | 132.3 MB | 111.1 MB | + +So it is 3.6x fewer instructions than the code it replaces, on top of being the +revision that asks in the right box: in the same 900-wide output the old code +lays the second paragraph out to x=929 and the third to x=910, both past the +edge, where this one keeps them at 877 and 889. + Widget draws do not move at all -- 449 either way -- so none of this touches a retained-layout rule. That matters for more than purity: **text is the load that makes a redundant draw expensive, and so the thing that shows when the @@ -994,6 +1022,10 @@ holds a merged branch; they are readable references, not places to build. "before" side of any measurement of the last two commits; `iris-size-old` is `43ce8c7` with the old patched counters, and is how the pre-#16 column above was measured. Copy `tests/revision_cost.rs` into either to compare. +`iris-old-cmp` (`43ce8c7`) and `iris-main-cmp` (`upstream/main`) are unpatched +worktrees with target directories of their own, for the instruction counts and +the reference renders above; `43ce8c7` calls it `Len::abs` where this branch +says `Len::px`, which is the only edit a copied fixture needs. ## Cautions