Record decided-box oracle blocker

This commit is contained in:
iris-ai committed 2026-09-18 15:07:15 -04:00
1 parent 3eda6f00c8
commit 39978ff8ea
2 files changed
+110 -29

No files matched your search

+41 -29
View File
@@ -16,19 +16,20 @@ baseline this work must preserve or improve. `/home/bob/repos/iris-pr18` has
since moved to a different WIP branch; do not use that checkout as #18.
The continuation is `/home/bob/repos/iris-layout-experiment`, branch
`wip/transparent-frames`, head **`4328eac`**, five commits over **`34cafb6`**.
It implements transparent frames, pins the two open failures, and corrects
`Scroll`'s content length, but it is not ready to replace #18:
`wip/transparent-frames`, committed head **`4328eac`**, five commits over
**`34cafb6`**, plus an uncommitted step 3/4 experiment. It implements
transparent frames, pins the two open failures, and corrects `Scroll`'s
content length, but it is not ready to replace #18:
- the shrinker disagrees warm versus cold at seed 2 (`repaint`) and seed 108
(`reorder`) at depth 5;
- the uncommitted experiment passes both focused regressions and the 114-test
suite, but every non-ignored fast-oracle case stops on a cold-layout
placement assertion, usually at `Text`;
- `many` and `resize` still do more work than #18 on a deep tree;
- a resolved `leftover` share does not yet narrow its child's frame;
- step 3 exposed a widget-contract question that must be planned before the
retained protocol can change; see **Step 3 stop** below.
The app's Iris pin is unchanged. The step 3 experiment described below was
reverted; the experiment checkout was clean at `4328eac` when last inspected.
The app's Iris pin is unchanged. Keep the experiment's uncommitted changes as
evidence; do not commit them as the protocol until the stop below is resolved.
## The two rules to protect
@@ -214,29 +215,40 @@ fresh-answer experiment (seeds 184, 246, 292 and 372).
### 3. Evaluate children in parent-decided boxes
**STOP: this step needs planning before implementation continues.** A direct
implementation was tried and fully reverted. It always kept the fresh answer,
made placement reuse-or-translate (asserting if the retained drawing did not
hold), asked `Span` children provisionally in the whole box before decided
placement, gave `Stack` overlays the sizing child's reported box, and changed
the random `Branch` tail to `Part::Of(40px..FULL)`. Both new focused tests
passed, but 17 ordinary suite tests failed.
**STOP: this step needs planning before implementation continues.** The first
17 suite failures were not sufficient evidence for stopping: most were test
fixtures that encoded the old paired-draw cost while their empty drawing used
only the answer. The experiment now separates answer-only pixel reads from
drawing reads, keeps answer and final-drawing contracts independent, asks
`Span` children provisionally with `Fill`, re-asks them in their decided
slots, narrows resolved-share frames, and re-asks local redraws at the
question their answer came from. It also fixes two real defects found along
the way: an overfull span falsely pinned itself to `far`, and a narrowed share
frame omitted a nonzero parent-extent start.
Several failures state a load-bearing contract contrary to this plan rather
than exposing another container bug. `ReadsBox` and `ReadsWidth` deliberately
read the offered box, report one quarter of it, and their tests require two
draws: one to answer and one in the answer-derived box. The tests' own comment
says those draws come in pairs. `a_widget_asked_again_on_another_layer_is_drawn_there`
likewise requires a second draw when placement changes the layer. Other
failures include root resize/one-step validity tests, region-node placement,
and `a_one_pixel_line_keeps_its_pixel_through_a_chain`.
That version passes the full 114-test suite, both focused regressions, the
region-node test, the one-pixel chain, and the wrap-at-remaining-room test.
The tests were checked individually before migration; geometry assertions
were retained, and drawing-dependency fixtures still use ordinary `px_len`.
The unresolved decision is therefore public widget semantics, not another
definition of measurement: either a widget must now guarantee that a drawing
holds for the answer box it reports (and the contrary tests, documentation,
and any real widgets must be redesigned), or placement sometimes has to run
the body in an answer-derived box, contradicting the decided-box rule. Do not
resume step 3 until that choice and its migration are written into the plan.
The release fast oracle then stopped in all eleven non-ignored cases during
*cold layout*, before any warm/cold comparison. The repeated shape is a leaf,
usually `Text`, asked provisionally in a `Within` box, reporting a smaller
answer, whose retained drawing contract covers only the provisional pixel
width. Placement into the reported box therefore hits the new
reuse-or-translate assertion. One representative assertion shows `Text` with
an X part of `FULL`, a centered answer span about 89.5 px wide, and a drawing
extent contract pinned at 45 px. A generated `Stack` also fails after
reporting a 178x21 px answer from `FULL` while retaining an `extent_len` pin
to `FULL`.
This is a real public-contract boundary, not a stale oracle: decide whether
every leaf as well as every container must guarantee that its provisional
drawing holds in the answer box it reports, and specify how `Text` establishes
that guarantee, or allow some answer-derived leaf evaluation while keeping
containers out of their own answers. The latter is a semantic distinction the
current `Widget` API does not express. Do not weaken the assertion, special
case `Text`, or resume the oracle until this choice is written into the plan.
Change placement so an answer-derived box never runs a container body.
Placing becomes reuse-or-translate. Remove the offer/measurement gate and
+69
View File
@@ -65,6 +65,75 @@ evaluations of a ten-widget subtree in one cold layout, from `Within(cursor..
far)` measuring rooms followed by `Fill(slot)` placing, with the span's
`extent_len` pin forcing a redraw at every box length.
## Original step 3 plan, preserved verbatim (planner, 2026-09-18)
This is the original idea from ai-app-2 `280fad7`, kept here even as the
handoff's stop notice changes with new evidence:
> ### 3. Evaluate children in parent-decided boxes
>
> Change placement so an answer-derived box never runs a container body.
> Placing becomes reuse-or-translate. Remove the offer/measurement gate and
> its retained bookkeeping only as each caller stops needing it; do not leave
> a parallel old path.
>
> Three current widgets must stop depending on measuring boxes they will never
> own:
>
> - `Span`: do not read `extent_len` unconditionally. Slots depend on `far`
> only when shares exist (the decided slot fills its part) or for negative
> direction; compute negative-direction slots from `total`. Pin the extent
> length only in those cases.
> - `Stack`: draw non-sizing children in `From(0..size)` on an axis where the
> sizing child's answer is `px`/`rel`, and `All` where it is `leftover`,
> instead of drawing them in `All` of the measuring room.
> - `Branch` in the random rig: express "the rest of my box" as
> `Of(40px..FULL)` rather than reading `extent_len(Y)`.
>
> Every drawing must hold for the answer box it supplies. The two focused tests
> from step 1 and the existing region-node and decided-box tests must pass here.
The surrounding seven-step implementation plan remains in `docs/HANDOFF.md`;
the quoted text above is the part whose interpretation is now blocked, so it
must remain available even if the live handoff is rewritten.
## Step 3 experiment after verifying the tests (worker, 2026-09-18)
The initial 17 suite failures mixed obsolete expectations with real defects.
`ReadsBox`, `ReadsWidth`, and `Measured` used pixel reads to compute only their
answer; failing `Counted` cases installed a box dependency without drawing
anything. Those fixtures encoded the old second draw inside the answer box.
Giving the painter answer-only pixel reads preserved their invalidation and
geometry claims while removing the obsolete paired-draw count. Separate
fixtures still exercise actual drawing dependencies with ordinary pixel
reads.
The experiment then reached a green 114-test suite. Its substantive findings:
- answer validity and final-drawing validity must remain independent all the
way through `draw_inner`; returning their old combined contract falsely
pinned wrappers such as `Pad` to provisional boxes;
- a repeated ask of one child replaces that child's provisional final-drawing
contract rather than intersecting both drawings forever;
- provisional `Span` asks fill their measuring room; `Within` immediately
tries to put the child in its own answer before the span decides anything;
- only an actually allocated share pins final span slots to `far`; an
overfull row with a requested but unallocated share uses fixed slots;
- a narrowed share frame is `Part::From(slot)` of the span's *extent*, not a
zero-based span in the forwarded frame;
- a local redraw re-asks the question that produced the retained answer and
marks the parent to restore any distinct final placement.
The release fast oracle then failed all eleven ordinary cases during cold
layout. Most failures were `Text`: its provisional drawing was pinned to a
pixel width that did not include the smaller box its answer selected. A
generated `Stack` showed the same class through a symbolic `FULL` pin. This
is stronger evidence than the original suite failures: the generated tests
are not asserting draw counts or the old two-draw protocol, and no warm state
exists yet. The open decision is whether the guarantee quoted above applies
to every leaf and how `Text` can establish it, or whether answer-derived leaf
evaluation remains legal while container evaluation does not.
## What the plan of 2026-09-18 got wrong (planner, same day)
The plan claimed the retained model rests on the frame's length being the