From 39978ff8ea5fae812861f27d1d0f8fd3d17cac66 Mon Sep 17 00:00:00 2001 From: iris-ai <4+iris-ai@noreply.localhost> Date: Fri, 18 Sep 2026 15:07:15 -0400 Subject: [PATCH] Record decided-box oracle blocker --- docs/HANDOFF.md | 70 +++++++++++++++++++++++++++------------------- docs/LAYOUT_LOG.md | 69 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 29 deletions(-) diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 3f1ca0c..216424e 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -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 diff --git a/docs/LAYOUT_LOG.md b/docs/LAYOUT_LOG.md index 79d4e74..111aa69 100644 --- a/docs/LAYOUT_LOG.md +++ b/docs/LAYOUT_LOG.md @@ -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