Commit Graph
4 Commits
Author SHA1 Message Date
iris-aiandClaude Opus 5 cbccfb600a Say a length that is zero, and share the seed a scan takes
A full sweep of #19, and the first review of f48e04e.

`Display for LayoutLen` leaves out every part that is zero, so
`LayoutLen::ZERO` printed as the empty string -- and `Debug` forwards to
`Display` since the last commit, so the four `assert_eq!`s in
`cases/deferred.rs` print nothing where a request of zero is, and
`scenario::describe` prints a `.width(0)` rule as `-`, which is what it
prints for a widget that has no rule at all. That file exists so a tree a
fuzzer found can be written out by hand; a value it cannot say is a hole in
the one thing it is for.

`Fixed::ceil_from_f32` took `next_up` of a `from_f32` that had already
clamped, and `next_up` wraps, so a measurement past the top of the grid came
back as the bottom of it. `from_f32` clamps deliberately because a float has
further to come from; the ceiling is the other way in from a float and now
holds to the same rule. The check goes beside the one `from_f32` already
had.

`Moves::depth` walked the move chain a second way, with its own copy of
`CHAIN_LIMIT` and without the assertion `walk` makes; it is `walk` now, so
the CPU counts the chain in one place and the shader's constant reaches
both.

`Harness::set_len` said it set a length "the way `.width()` sets one" and
wrote the whole rule instead, dropping any bound beside it. A case that set
a bound and then a length would have passed with no bound at all.

Three rigs each spelled "one seed, or a range of them" by hand -- the class
the eleventh sweep closed for reading a parameter and not for this. There is
one `rig::seeds` now. `cases/deferred` was last in `suite.rs`'s otherwise
alphabetical list.

`diag::outside` writes out `AxisHolds::contains`'s four clauses to say which
one refused a reuse; a debug assertion now catches a fifth clause added
there and not here, which would leave a refusal counted and unexplained.

`Sow::bound`'s comment recorded an open hole reached by seeds 4 and 196 at
depth 5 -- but `generated.rs` says seeds stopped naming those trees when the
leaves grew images, and 600 depth-5 trees over all sixteen cases agree warm
against cold with every bound a fraction. The comment says what is true now
and why the generator still grows pixels.

Format, workspace clippy under -D warnings with and without
layout-diagnostics, 208 ordinary and 212 diagnostic tests (207 and 211
before, plus the one this adds), and the cold dump byte-identical to
f48e04e across all 34,986 boxes. The three seed scans were not run: nothing
here can move a box, which the dump confirms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 22:04:07 -04:00
iris-ai 8780b40bb7 Resolve deferred size comparisons before allocating span slots 2026-09-20 16:50:18 -04:00
iris-aiandClaude Opus 5 98d4e98a29 Describe a tree before building it, so a failing seed can be reduced
The oracle grew its trees from a seed and the shrinker grew its own, with
every scenario written out on each side. So a failure the oracle found could
not be handed to the shrinker: there was no tree to pass it, only a seed, and
a seed cannot be made smaller. The shrinker could only grow its own trees and
hope to meet the same shape, which it does not -- 20,000 of its trees never
reproduced what the oracle's seed 18 shows at depth 6.

`iris::random` now answers with a `Plan`: `plan(seed, depth, &edits)` draws one
out of the random stream and `build(rsc, &plan)` makes the widgets, where
`grow` did both at once. Every draw happens in the order it always has, so a
seed still means the tree it meant -- checked by running the oracle at 1000
seeds of depth 6 before and after and getting the same three failures with the
same boxes. `Plan::smaller` reduces one, `Plan::edited` applies an `Edits` to a
tree that already exists, and `tests/scenario/` holds the fifteen cases both
rigs now run over the same trees.

A span keeps the order it holds its children in apart from the children
themselves, so detaching, attaching and reordering leave the widgets made in
the same order and two builds still line up index for index. `Tree::detached`
is gone: `Spanned::spares` is everything made for a span that it does not
hold, which is what both of those were.

`tests/cases/plan.rs` pins the three properties the rest rests on: editing a
plan is growing one with those edits, every simplification is smaller than
what it came from, and reducing ends. The second caught this change's own
defect, where dropping a side of a `Branch` duplicated another and grew the
tree by four widgets.

What it found, on its first run: `SHRINK_SEED=18 SHRINK_DEPTH=6
SHRINK_CASE=repaint-some` reduces 277 widgets to 5. A scroll inside a scroll,
the inner one owning a movable region, and only the text at the bottom marked
for redraw -- and the span lands 24px out, which is exactly the sized child's
height. `git bisect` names `95fb4f9`, where `Masked` began reporting its box
rather than its inner's size, so what the outer scroll is told its content
measures now depends on whether the inner subtree was redrawn this frame.
`tests/cases/unsettled.rs` has it written out, ignored until it is fixed.

Checked: fmt, clippy over all targets with -D warnings, the workspace tests
(79 + 11 + 15, one ignored for the defect above), and the 100-seed oracle over
all fifteen cases at depth 4. The shrinker at 400 seeds of depth 5 now fails,
which it did not before running the oracle's trees and cases: seeds 2 and 288
on region-node and 174 and 175 on repaint-some are unreduced leads.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 15:58:31 -04:00
iris-aiandClaude Opus 5 cb955f1023 Link the ordinary tests once, and keep their debug info to line tables
Eleven `tests/*.rs` were eleven binaries, each linking the whole graph --
`wgpu` and all -- to run a handful of cases. They are modules of one target
now, under `tests/cases/`, and `cargo test --test suite layout::` still picks
one out. The fuzzers and the `*_cost` measurements stay their own targets:
they are run on their own and want to be selectable without building the
rest.

`profile.test` takes `debug = "line-tables-only"`, which is what a backtrace
here actually reads; the type and variable information was the bulk of what
the linker was writing.

Measured on this machine, rebuilding `iris`'s test targets after a change to
the crate: 14.3 s before, 9.8 s with one target, 7.7 s with both. `target/`
went from 45 GB to 13 GB. The suite still passes 102 tests, and the binary
still carries `.debug_line`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 03:00:43 -04:00