diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 4216070..a5fe256 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -8,7 +8,7 @@ log. Canonical Iris `main` is **`ca2b4b2`** (#17, the headless rig). **#18 `split/18-position-chain`** is open in `/home/bob/repos/iris-pr18`; its local -head is **`d21a215`**, eighty commits, pushed. Built-in alignment is +head is **`45a7176`**, eighty-one commits, pushed. Built-in alignment is complete there; see "Built-in alignment" below for the retained-layout details. No PR reviews were present when checked on 2026-09-15. @@ -167,15 +167,16 @@ in, and it is compiled out of the release runs above. ## Verification -**At `e166e00`**, the current head: +**At `45a7176`**, the current head: - `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -- -D warnings`, `cargo test --workspace`: sixteen targets green, 83 suite tests, 17 core unit tests, 11 generated cases. What stays ignored is the long runs and the profiling rigs; no known defect is ignored any more. - The release oracle at 100 seeds in 14.3 s, **all fifteen shrinker cases at - 400 seeds of depth 5** in 57 s, and **1000 seeds of depth 6** in 145 s. The - last two pass for the first time. + 400 seeds of depth 5** in 57 s, and **1000 seeds of depth 6** in 143 s. The + last two pass for the first time, and have kept passing across every + commit since. - `view`, `minimal` and `random` render byte-identical at 1920x1200 against `98d4e98`. `tabs` and `text` changed twice on purpose: `08c9d5a` moved an antialiased edge by less than a pixel (see "Performance") and `2bc6bdf` @@ -758,10 +759,29 @@ pixels and `Holds`. Decided with Bryan on 2026-09-15. point that need not contain the box the part was drawn in. What it allows for has two parts and they are not the same shape. - **The two routes to a length** -- composed down the chain against - measured against the window -- get three half steps either side. That is - the floor: two fires the `Holds` assertion on eleven generated cases. - Four was tried and was overshoot, and tightening it moved none of the - rig's twenty-five work counters, so slack here buys no reuse (`38eba54`). + measured against the window -- get two half steps either side, since + `45a7176` made the walk round once instead of once a level. It was three + while composing rounded per level, and four before that, which was + overshoot. Tightening it has never moved one of the rig's twenty-five + work counters, so slack here buys no reuse. + + **One half step further is arithmetically available and deliberately not + taken.** The `Holds` assertion is quiet at one, and the whole-of-a-box + case becomes an exact identity. What stops it is shrinker seed 220 on + `reorder`, which then lays out differently warm than cold: too narrow a + range is supposed to cost a redraw and nothing else, and there it + re-breaks a wrapping text, whose reported width moves a `Branch` onto + its other subtree. **That is the next thing to chase** -- it is the + unsettled-text family rather than a rounding question, it reduces to ten + widgets, and closing it is what lets this go lower: + + ```sh + SHRINK_SEED=220 SHRINK_DEPTH=5 SHRINK_CASE=reorder \ + cargo test --release --test shrink -- --ignored --nocapture + ``` + + The tree is `Scroll(X) { Pad as a region node { Span(X) { Branch, + Span(X){ wrapped text, one-line text } } } }`. - **The multiply on the way in** gets one more step at the top of the range and nothing at the bottom, since truncation only ever drops. The whole of a box has no multiply in it, however many pixels are added to it, and @@ -954,9 +974,10 @@ Queued from this work, in order: since `a8898aa`. Still awaiting Bryan: whether a `Max` narrows the box the child draws in, or only what the parent reports for it. -- **Compose in `i64` and narrow only when storing** (Bryan, 2026-09-16). - Chosen for the share spread; **what it buys is not that**, found on - 2026-09-16 and worth reading before starting. +- ~~**Compose in `i64` and narrow only when storing**~~ -- **done in + `45a7176`**, and what it bought is below. The rest of this item is kept + because the measurement in it is what stopped the work being aimed at the + wrong thing. The range inside a single operation is already protected -- `Fixed::mul` widens to `i64` for the product, `Holds::through` does all of its @@ -986,19 +1007,20 @@ Queued from this work, in order: pushes a value across the `floor` -- which is what moved `tabs`'s corner arcs by a pixel at `08c9d5a`. - What is left to buy is **layout's own decisions**, which is not nothing: - the `Span` leftover boundary and the clamp crossover are structural - decisions taken on a pixel comparison, `Holds` validity is a pixel - interval, and warm-against-cold agreement is the thing every rig here - measures. The success test is `Holds::through`'s two-route allowance - shrinking from three half steps toward zero, in debug where the assertion - is live. + What it bought is **layout's own decisions**: `Holds::through`'s two-route + allowance went from three half steps to two, and the whole of a box now + maps back to one step rather than one step per level of nesting. - Two things to decide before starting: how many fractional bits the - intermediate keeps, since chained multiplies accumulate them and an `i64` - runs out too; and whether it keeps `UiSpan::within` inside the inliner, - which is what actually moves cycles there -- a `Wide` that makes the body - bigger loses on the axis the truncating multiply won on. + **And it was free.** 1,880M instructions and 755M cycles against 1,908M + and 760M, medians of 25 with all twenty-five work counters identical. + Two things paid for the widening and are the reason to keep them: a + *length* composes on its own in two multiplies a level rather than the + four both ends cost, since where the parent sits falls out of the + difference; and the pixel term takes its fraction on the ordinary grid, so + only the fraction itself -- the part that compounds multiplicatively -- + needs the room. A third, skipping a parent that spans its own box, cost + 18M instructions and is not there, the same verdict `UiSpan::within`'s + short-circuits got. Other queued work, in dependency order: