Record the leftover boundary, and close the reorder case
The shrinker's `reorder` case is no longer red: its two seeds were a span deciding whether anything was left over on a box length its own answer had produced, which comes back a few bits off. `5ed9e87` in `/home/bob/repos/ iris-pr18` moves that boundary by `HOLDS_EPSILON_PX` of room instead of softening the comparison, so the validity range stays exact where generated seed 16 needs it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
76334cd5aa
commit
1a73aba1cd
1 file changed
+53
-22
+53
-22
@@ -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 **`d3b0ebf`**, fifty commits. Built-in alignment is complete there;
|
||||
head is **`5ed9e87`**, fifty-one commits. 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.
|
||||
|
||||
@@ -65,20 +65,25 @@ rewrite:
|
||||
- `Span`'s leftover/no-leftover split is a strict layout decision, not a
|
||||
rounding tolerance. Its `Holds` range must use the same exact divided
|
||||
boundary as drawing; a tolerant endpoint retained zero-height children at
|
||||
the boundary in generated seed 16.
|
||||
the boundary in generated seed 16. `5ed9e87` moves that boundary rather
|
||||
than softening it -- see "The leftover boundary" below.
|
||||
|
||||
`core/src/ui/holds.rs`, the retained tests, and the generated cold-layout oracle
|
||||
pin those rules. Seeds 10 and 86 are now in the ordinary generated set.
|
||||
|
||||
## Verification at `d3b0ebf`
|
||||
## Verification at `5ed9e87`
|
||||
|
||||
- `cargo fmt --all --check`
|
||||
- `cargo build --workspace --all-features`
|
||||
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`
|
||||
- `cargo test --workspace --all-features`: 88 passed, 10 ignored
|
||||
- The release generated cold-layout oracle passed 100 seeds in 65.5 s.
|
||||
- The release shrinker passed both `repaint` and `resize` at 300 seeds each:
|
||||
26,001 widgets per case, largest tree 331 widgets.
|
||||
- `cargo test --workspace --all-features`: 89 passed, 10 ignored
|
||||
- The release generated cold-layout oracle passed 100 seeds in 68.5 s.
|
||||
- The release shrinker passed **all five** cases -- `resize`, `repaint`,
|
||||
`resize-repaint`, `reorder`, `size-change` -- at 1000 seeds of depth 6:
|
||||
159,024 widgets per case, largest tree 587 widgets. At the ordinary 300
|
||||
seeds of depth 5 it is 26,001 widgets per case, largest tree 331.
|
||||
- `tabs`, `view`, `minimal`, `text` and `random` render byte-identical at
|
||||
1920x1200 against the same worktree without `5ed9e87`.
|
||||
- `tests/drift.rs` passed its 20,000-move exactness check in release mode.
|
||||
- The seeded `random` example, live-resized from 1920x1200 to 1280x800, is
|
||||
byte-identical to a cold 1280x800 render. Both PNGs hash to
|
||||
@@ -175,11 +180,12 @@ tighter figures.
|
||||
- Text shaping is retained separately from line breaking. A greedy line break
|
||||
remains valid from its longest produced line through the width at which it
|
||||
was made, and `TextView` reports that interval through `Painter::holds`.
|
||||
- `Span`'s decision to distribute `leftover` is a pixel question. Its validity
|
||||
interval is split exactly at the length where fixed parts fill the box;
|
||||
pure `leftover` children are undrawn on the no-space side. Exact/open ranges
|
||||
are for hard widget decisions; the ordinary tolerant ranges remain for
|
||||
accumulated coordinate rounding.
|
||||
- `Span`'s decision to distribute `leftover` is a pixel question. The room to
|
||||
divide is `len * fixed - total.px`, and under `HOLDS_EPSILON_PX` of it is
|
||||
none; pure `leftover` children are undrawn on the no-room side. The validity
|
||||
interval is split exactly at that moved boundary. Exact/open ranges are for
|
||||
hard widget decisions; the ordinary tolerant ranges remain for accumulated
|
||||
coordinate rounding.
|
||||
- `Scroll` reports its content's first measured size. Its drawing can survive
|
||||
container-length changes only over the interval in which clamping and its
|
||||
current offset do not change.
|
||||
@@ -199,9 +205,7 @@ tighter figures.
|
||||
|
||||
## Built-in alignment
|
||||
|
||||
Committed as `d3b0ebf` in `/home/bob/repos/iris-pr18`. The shrinker's
|
||||
`reorder` case remains red at its base `8220a78`, so that failure is
|
||||
pre-existing and unrelated.
|
||||
Committed as `d3b0ebf` in `/home/bob/repos/iris-pr18`.
|
||||
|
||||
What is in it: `align` is a widget property beside `region_node` and the size
|
||||
rule, `Aligned` is deleted, `.align()`/`.center()` set the property, and the
|
||||
@@ -288,6 +292,35 @@ length the box takes and the drawing holds for that length alone.
|
||||
A `debug_assert` that a reported non-leftover size does not exceed the box it
|
||||
drew in would have caught both immediately, and is still worth adding.
|
||||
|
||||
## The leftover boundary
|
||||
|
||||
Fixed in `5ed9e87`, which closed the shrinker's `reorder` case. Neither of its
|
||||
two red seeds was about reordering.
|
||||
|
||||
A span's box in pixels, compared with what its fixed and relative children
|
||||
fill, is the same number whenever the parent sized that box from the span's own
|
||||
answer -- and the box comes back through the chain a few bits off. So
|
||||
`0.00003 px` decided whether a `leftover`-only child existed: warm rounded
|
||||
under and left it undrawn, cold rounded over and drew it at zero length. Both
|
||||
layouts are stable and the pixels are identical either way, which is why only
|
||||
the warm-against-cold oracle could see it.
|
||||
|
||||
**A structural decision may not be taken where boxes structurally land.** The
|
||||
fix is not a tolerant comparison -- that is what generated seed 16 punished --
|
||||
but a boundary moved by `HOLDS_EPSILON_PX` of room, with the validity range
|
||||
split exactly at the moved boundary. What it gives up is a share of under a
|
||||
twentieth of a pixel. `tests/unsettled.rs`'s
|
||||
`a_box_that_only_rounds_past_its_fixed_children_leaves_nothing_over` is the
|
||||
six-widget regression, shrunk from 266; it needs the span above the one that
|
||||
divides, because without a box composed through it both trees round the same
|
||||
way.
|
||||
|
||||
`Scroll`'s `content_len <= container_len` sits on the same coincidence but is
|
||||
continuous there -- it chooses between two `Holds` ranges that both contain the
|
||||
current length, so a rounding difference costs a redraw rather than a
|
||||
different layout. Checked while fixing this; nothing else reads a box in
|
||||
pixels to decide something structural.
|
||||
|
||||
## Rigs and reproduction
|
||||
|
||||
Ordinary framework verification:
|
||||
@@ -349,15 +382,13 @@ child-placement API. `docs/LAYOUT.md` §2 is stale: it still describes
|
||||
|
||||
**Built-in alignment and size goes on #18 rather than after it** (Bryan,
|
||||
2026-09-15: #18 is unreviewed and already large enough that most lines get read
|
||||
anyway). The size half landed as `8220a78`; the alignment half is in the
|
||||
working tree and described below.
|
||||
anyway). The size half landed as `8220a78`, the alignment half as `d3b0ebf`.
|
||||
|
||||
Do not restore `OnResize::Translate`; retained translation is now expressed by
|
||||
the same `Holds` contract and box chain.
|
||||
|
||||
Queued from this work, in order:
|
||||
|
||||
- The shrinker's `repaint` case, via the replacement placement design above.
|
||||
- Delete `OrthoSize`. It is redundant now that size is built in: a span should
|
||||
read its own rule on the orthogonal axis and, where that is fixed, skip
|
||||
reading its children's orthogonal sizes entirely, which is what `Full` does
|
||||
@@ -369,10 +400,10 @@ Queued from this work, in order:
|
||||
clamp resolved where the box is decided also fixes `MaxSize`'s reading of
|
||||
`px_size`, which pinned its interval to one exact box on both axes and
|
||||
redrew its whole subtree on any resize. The clamp boundary is a hard layout
|
||||
decision, not a tolerance: its `Holds` range must be exact and split at the
|
||||
crossover, the way generated seed 16 taught for `Span`.
|
||||
- The shrinker's `reorder` case, which is red at `8220a78` and was not
|
||||
introduced by any of this.
|
||||
decision: its `Holds` range must be exact and split at the crossover, the
|
||||
way generated seed 16 taught for `Span` -- and the crossover itself has to
|
||||
sit off the length a box structurally lands on, the way `5ed9e87` taught.
|
||||
See "The leftover boundary".
|
||||
|
||||
Other queued work, in dependency order:
|
||||
|
||||
|
||||
Reference in new issue
Block a user