Record the tenth sweep, over the deferred request system

This commit is contained in:
iris-ai committed 2026-09-20 18:25:03 -04:00
1 parent e6a035d06e
commit 992a4a2e97
2 files changed
+114 -8

No files matched your search

+93
View File
@@ -6,6 +6,99 @@ 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`.
## Tenth sweep: the deferred request system (2026-09-20)
Over the part of #19 no earlier round reviewed -- `76aaf06` and `de1eb7e`
(the bound rules and the rule/widget split), `8780b40` (deferred comparisons)
and `0e838e9` (the invalidation fix) -- 2,243 inserted lines over 32 files,
with `core/src/widget/request.rs`, `MaxSize` and the deferred cases new. Ten
findings, all in `4cb6f68`.
- **A bound's held length was looked up a second time, through a value that
could not say which end.** `Bound::outside` returned `Option<Outside>` and
the caller asked `Bound::at(outside)` for the length, which `expect`s an end
the enum says nothing about -- `at(Shorter)` on a bound with no floor
panics, and only the pairing of the two calls kept it from happening.
`outside` already had the length in hand (`held`), so it now returns it;
`Outside` and `Bound::at` are deleted, and the state that could panic
cannot be written.
- **A pixel bound pinned the rel base it was not read against.**
`Painter::measured_request` recorded a rel-base dependency for any bound at
all, so a measured share under `Min(px(80))` was invalidated by a change to
a base its answer does not depend on. This is the class `0e838e9` fixed one
instance of; `Placing::ask` already asked the narrower question inline, so
the question is now `Bound::has_fraction` and all three callers ask it.
- **One question about a pair, written out three times.** `[bound.min,
bound.max].into_iter().flatten().any(|len| len.rel != Rel::ZERO)` appeared
in `SizeRule::has_fraction` and again in `Placing::ask`, over a pair the
framework names. It is `Bound::has_fraction` once.
- **Three buffers reused for their capacity, on an invariant nothing
stated.** `draw_at` now hands the painter the old draw's `textures`,
`primitives` and `request_deps`, which is only sound because every path to
it goes through `remove`, which drains them. A drawing over a buffer that
still held primitives would record them twice and free them once. A
`debug_assert` says so where they are taken.
- **Two names and two spellings for one switch in the rigs.** The walk that
drops a generated tree's bounds was written out in `layout_dump.rs` and
`layout_diagnostics.rs`, under `IRIS_DUMP_UNBOUNDED` read with
`var_os().is_some()` in one and `IRIS_UNBOUNDED` read with the file's own
`env` helper in the other. It is `Plan::drop_bounds` and `IRIS_UNBOUNDED`
in both, and the dump's module comment says so.
- **`Span` wrote its gaps twice and read its allocation three ways.** The gap
total is `Span::gaps`. In the placement loop `len`, `shares` and "not drawn
at all" were three separate matches on whether the row was allocated, two
of them deciding one child's length: one match now gives all three, so the
allocated and plain rules are read side by side.
- **`Stack` spelled "the child that sizes it" a second way** in
`size_request`, with two arms answering `LEFTOVER`, where `draw` resolves
the same thing once.
- **`Pad` spelled its own padding a second way.** `Padding::along(axis)` is
the sum of the two sides, which `draw` adds back and `size_request` insets
by.
- **Comments that described something else.** `with_requests` said nested
painters keep discovery from overwriting its buffers, where the hazard is a
child *drawn* mid-row; `Painter::allocate`'s doc described the window it
holds for rather than what it does; `minimum_request` had none;
`RequestArena::allocate` said "one scope of nonnegative shares", which is
not this codebase's vocabulary; and `redraw_updates` was left mid-rewrap,
with "the set" naming a `BTreeSet` that is now a `BinaryHeap`.
- **A live explanation deleted with the path it was not about.** The comment
saying a span carries its children's leftover weight whole rather than
collapsing it per level -- the rule the handoff still lists as wanting
confirmation -- was replaced by one about discovery. Both paths run; both
are now described.
Two findings of the `as i32` kind were **looked at and left**. The allocator
narrows i128 prefix sums and i64 segment totals to `Px` with `as i32` rather
than `fixed::narrow`, which clamps; but `Fixed::add`, `sub` and `mul` all
wrap deliberately (`MAX` is documented as "compared against, never added
to"), so wrapping is what the ordinary path does with the same overflow, and
`narrow` is for ranges. The epoch check in `RequestArena::segment` stays a
release `assert`: a retained `RequestedLen` would otherwise read a node
belonging to another widget and answer silently, which is worse than the
compare it costs. The negative-weight check beside it is a caller bug like
`div_int`'s and is now a `debug_assert`.
Two things the sweep did not change and somebody should decide:
- **The generator's leftover density halved** when `76aaf06` grew bounds:
`Sow::rule` draws `LEFTOVER` 1 time in 8 where `Sow::len` drew it 1 in 4,
and `Free` 2 in 8 where it was 1 in 2. The seed scans are the main defence
for share logic, so the corpus now exercises it half as often. Restoring it
costs a new dump baseline and three fresh scans.
- **`MaxSize` holds `x` and `y` with a hand-written axis match**, where the
framework names every other pair (`Bounds`, `Declared`, `Size`) and indexes
it. Left because the fields are the constructor surface `max_width` and
`max_height` build, and `impl_axis_index!` on a widget reads oddly; it is
three call sites inside one file.
Verified at `4cb6f68`: format, workspace clippy under `-D warnings` with and
without `layout-diagnostics`, 197 ordinary and 201 diagnostic workspace
tests, the cold dump byte-identical to `0e838e9` across all 34,986 boxes, and
all three seed scans (400 at depth 5 in 69.02s, 1,000 at depth 6 in 174.87s,
2,000 at depth 4 in 330.39s). The scans were run because the rel-base fix
changes what is invalidated, which is exactly what warm-against-cold checks.
## Performance sweep of #19 (2026-09-20)
`0e838e9`, by Codex.