diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index b40f613..8202196 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -6,8 +6,8 @@ found is in `docs/LAYOUT_LOG.md`. ## The Iris layout repair is submitted -**Iris PR #19** (`layout/one-ask`) replaces closed #18. The tip is `1ebd4d3`, -and past the reviewed `cadfba0` it is five rounds, each described in +**Iris PR #19** (`layout/one-ask`) replaces closed #18. The tip is `69ba915`, +and past the reviewed `cadfba0` it is six rounds, each described in `docs/LAYOUT_LOG.md`: - **The repair**, `add6774` and `84dad21` -- collapsed-share placement, @@ -19,6 +19,10 @@ and past the reviewed `cadfba0` it is five rounds, each described in - **A clarity sweep**, `3da1c71` through `1ebd4d3` -- naming the pairs layout returns, `Span::slot`, a diagnostic that printed the rel base while calling it the box, and `in_parent` matching a place's own cases. +- **A quality sweep**, `aea0387` through `69ba915` -- a kept contract judged + against the placed box rather than the box asked about, two things nothing + read, three reuse rejections the diagnostics could not see, and a fuzz case + that ran only in the long scan. The settled design of the last three is in `docs/LAYOUT.md` under "Three names, and the one argument that says them". Bryan settled the API over diff --git a/docs/LAYOUT_LOG.md b/docs/LAYOUT_LOG.md index 0b24b01..93b279c 100644 --- a/docs/LAYOUT_LOG.md +++ b/docs/LAYOUT_LOG.md @@ -6,6 +6,72 @@ nothing here is rediscovered. Each entry says who found it and when. it (settled design, the measurement method) belongs in `docs/LAYOUT.md`, and the current plan is in `docs/HANDOFF.md`. +## Quality sweep of the whole branch (2026-09-20) + +A fourth sweep, over the layout core, the arithmetic, the atlas, the sensor +walk and the fuzz rig rather than over naming. Four findings, all on +`layout/one-ask` past `1ebd4d3`; the cold dump is byte-identical to it and +all three seed scans pass (400 at depth 5 in 65.09s, 1,000 at depth 6 in +161.27s, 2,000 at depth 4 in 301.90s). + +**A kept contract was judged against the wrong box** (`713e3e7`). `redraw` +keeps the narrower guarantee a parent holds when the fresh drawing covers +it, so widening and narrowing back do not churn the parent. It asked +`was_holds.contains(.., active.placement)` -- where the answer put the +drawing -- when `holds` is about `active.region`, the box the drawing was +made in. The two differ on every axis a widget reported less than it was +offered, so such a widget marked its parent every time its contract +widened. Cost, not geometry: accepting is always safe, since `region` is +always inside the old range, so refusing only escalates. `resize` and +`try_reuse` both already ask about `region`. +`widening_what_a_drawing_holds_for_does_not_relay_out_the_parent` fails at +`1ebd4d3` and passes with the line changed; the existing +`widening_and_restoring_a_contract_does_not_invalidate_its_reader` cannot +see it, because its leaf reports `LEFTOVER`, which fills its box. + +**Two things nothing read** (`aea0387`). `ActiveData::size_deps` was written +on every draw and cleared on every undraw, and read nowhere -- a `Vec` per +active widget. The `Painter`'s own copy is the live one, used in `draw_at` +to record whoever asked about a child it did not draw. `SizeRule::apply` +had no caller and would have been wrong with one: it answers the rule's own +length where `draw_at` resolves a fraction against the rel base first. + +**Three reuse rejections said nothing** (`8088a1f`). Of the eight +rejections in `try_reuse`, a changed inherited mask counted and traced +nothing, an undrawn record traced without counting, and a changed +region-node choice counted without tracing. The mask one is what this +branch's repair was about, so the rig could not answer "why did that +redraw?" for it. Adding a counter meant editing a variant list and a name +list at the same index; they are one declaration now. + +**A fuzz case ran only in the long scan** (`69ba915`). `Case::SizeResize` +was in `ALL` and in none of `generated.rs`'s `case!` invocations, so the +size-then-resize order -- which the enum's own comment argues is not the +same test as the other order -- was never checked by `cargo test`. The +tests and the list of which cases have one come from one macro invocation, +and a case missing from it now fails a test. + +### Tripped a rule and left as it stands + +- `Span` reads every child's cross length through `place_at(..).len(!axis)` + even where `has_exact_size(!axis)` makes it moot. The read looks like an + unwanted dependency, but `depend_on` only matters for a child that is not + in `children`, which is how `undraw` keeps a measured-then-dropped child + reachable. For a placed child it does nothing. +- `PixelRegion::contains` is inclusive at both ends, so two adjacent + widgets both claim the boundary step. Senses on one layer never block + each other, so both receiving it is what the design says. +- `CursorData::sense` is meaningless until `should_run` fills it, which the + code says in place and proposes a prepare stage for. A real + unrepresentable-state finding, but it is the event API's shape rather + than this branch's. +- `Wrapper` with no child answers `Size::default()`, which is `LEFTOVER`. + It reads as "nothing" but matches `impl Widget for ()`, whose comment + says a gap takes the default length so a span gives it a share. +- `ALL` in `tests/scenario/mod.rs` is still a hand-kept list of every + `Case`; `Case::name`'s match is the compiler-checked one. A variant left + out of `ALL` is invisible to the shrinker's `--case` selection too. + ## Naming and logic sweep (2026-09-19) Settled with Bryan across one session, on the branch past `58ce74d`. Nothing