Update alignment handoff

This commit is contained in:
iris-ai committed 2026-09-15 23:13:40 -04:00
1 parent 085fc97334
commit 76334cd5aa
1 file changed
+40 -21
+40 -21
View File
@@ -8,11 +8,9 @@ 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 **`8220a78`**, forty-nine commits, pushed to the fork. Built-in
alignment is **in the working tree at that checkout and not committed** -- see
"Built-in alignment, in flight" below before touching it. No PR reviews
were present when checked on 2026-09-15; the verification summary is posted on
the PR.
head is **`d3b0ebf`**, fifty 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.
The current head completes LAYOUT.md §2's position chain and the requested
`leftover` behavior. A child whose length is only `leftover` is not drawn when
@@ -72,13 +70,20 @@ rewrite:
`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 `8220a78`
## Verification at `d3b0ebf`
- `cargo fmt --all --check`
- `cargo build --workspace --all-features`
- `cargo clippy --workspace --all-targets --all-features -- -D warnings`
- `cargo test --workspace --all-features`: 85 passed, 10 ignored
- `cargo test --release --test generated -- --ignored
a_long_run_of_seeds_agrees --exact`: 100 seeds passed in 67.6 s
- `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.
- `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
`1d397c57b9914a2e596fa907029bc6aab4629e4d74deb0715e81325c703bcdb3`.
The run used the Venus adapter backed by the host RX 7900 XT.
- `minimal`, `text` and `view` render byte-identical at 1920x1200 across
`8220a78`. `tabs` differs only in the widget count it prints about itself,
which is two wrapper types smaller -- so it is no longer a byte-identical
@@ -90,7 +95,13 @@ pin those rules. Seeds 10 and 86 are now in the ordinary generated set.
before and after replay. Every comparison had zero differing pixels. The
live-resize image is also byte-identical to the cold 900x1200 image.
The final pre-submit review was run in four passes. The region-node review
The built-in-alignment pre-submit review was run in four passes. It caught
three distinctions the smaller tests had missed: an answer's validity must
include the drawing made in its final placed box; a region-node box is resolved
through its parent move rather than through its own move twice; and boxes with
equal dimensions but different positions still need the parent that placed
them. The 100-seed oracle and both 300-seed shrink cases pass after those
fixes. The earlier region-node review
caught an index-reuse hazard when removing a node; its move entry now remains
alive until every descendant has migrated. The generated oracle then exposed
the exact `Span` threshold described above. The earlier retained-layout
@@ -134,7 +145,17 @@ tighter figures.
not, and `Scroll` never reasserts it while drawing.
- The first box a parent asks about is the offer. A later box chosen from the
child's answer is the final box, not another independent answer. Dirty
widgets are re-asked at the offer and only then drawn in the final box.
widgets are re-asked at the offer and only then drawn in the final box. An
offer composes through its ancestors' offers, not through their current
placed boxes.
- An answer is reusable only where both its measurement and the drawing made
in its final placed box remain valid. The final drawing's `Holds` interval
is translated back into lengths of the offered box and intersected with the
answer's interval.
- Equal box lengths do not imply equal placement. An ordinary widget whose
offered and current boxes differ in position must involve its parent again;
a region node can settle itself only when its own alignment, rather than a
container override, determines the final box.
- A retained drawing can be reused only when its `Holds` interval contains the
new pixel box on both axes, its parent node is unchanged, its region-node
choice matches the retained structure, and the widget is clean. A valid
@@ -176,13 +197,11 @@ tighter figures.
being paid for. The generated oracle compares within 0.05 and `unsettled.rs`
runs too few frames to reach it, which is why `tests/drift.rs` exists.
## Built-in alignment, in flight
## Built-in alignment
Uncommitted in `/home/bob/repos/iris-pr18` on top of `8220a78`: 87 tests, fmt
and clippy clean, the 100-seed generated oracle green, and the shrinker's
`resize` case green at 300 seeds. The shrinker's **`repaint` case is red**, for
the reason in "Placement cannot be applied after the fact" below. Its `reorder`
case is red at `8220a78` too, so that one is **pre-existing and unrelated**.
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.
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
@@ -192,10 +211,10 @@ runtime. Region nodes had **no generated coverage at all** before that.
### Alignment is two fractions, not four directions
Decided 2026-09-15 (Bryan). A widget's alignment is one `f32` per axis, so a
quarter of the way along an axis is expressible. `AxisAlign`'s three cases
become named constants over that number, which is what every expression
quarter of the way along an axis is expressible. `AxisAlign`'s three familiar
positions are named constants over that number, which is what every expression
already uses: the layout math only ever reads `AxisAlign::rel()`, so nothing
downstream changes shape. The in-flight tree still has the enum.
downstream changes shape.
The default is **the middle on both axes**, because the two edges are the ones
that assume a direction -- which edge is the near one depends on the writing
@@ -220,7 +239,7 @@ state carries it.
the top widget's `placed` is recomputed while an ancestor's shift carries the
whole subtree. Measured 7,048,813 where a cold layout says 456.
The replacement, not yet written: alignment applies in the two places that
The replacement applies alignment in the two places that
already exist and are exact. Where the size is known before drawing, from a
rule, `declared_box` hands the child its aligned box directly -- one draw, no
move. Where the size is only known after drawing, the widget is **re-asked in