Measured at a888717 and at the new f6242aa on wip/hint-first, with the
inset experiment recorded as tested and rejected. The plan is now review,
render and land.
Re-measured the work counters at a888717 (unchanged from adbedaf), and
tested the handoff's claim about a positive span pinning `far`: without the
pin, seed 1's resize goes from 44 draws of 13 widgets to 20 of 9. The pin is
worth removing, and what stops a sound removal is that no `Part` can say
"from the cursor to the end of the box" without naming the box's length.
The pre-submit review of the six one-ask commits found a scroll placing
content that fits into a window-length box rather than its viewport, and
three comments still calling window lengths frame lengths.
Every check in the table was run over the branch head with nothing else
running and no edit in flight: fmt, both clippy feature sets, the suite,
and all three fuzzers over sixteen cases.
The record's boxes are part, asked and placed, LayoutHolds carries window
ranges beside its two pins, and what is left of the layout plan is the
retained cost and the review of the branch as one diff.
Step 3 is done: against #18 the render set is byte-identical but for two
pixels of antialiasing in random and one padded block in text moving a
pixel, and a live resize of random matches a cold render at that size
exactly. The cost table is re-measured at adbedaf, where the fuzzer's own
Branch was found pinning the window and hiding what the change costs.
Step 2 of the layout plan is done in the experiment checkout, at 1512d84
and 23523ee. The handoff carries the commits and what is left; LAYOUT.md
carries the settled rule, which is now one coordinate unit with the frame
a length of it and both pins beside each other; the log carries what
implementing the plan corrected in it, including the four that would have
shipped as wrong layout and the two rig gaps that hid them.
The handoff now describes wip/one-ask at 3091fb8: a widget draws once in
the box it is asked in, its answer is placed by re-expressing the drawing,
and nothing is drawn again in a box an answer chose. The log records what
the step 3 plan got wrong -- it kept the second draw whose measurement
bit could not be defined, demanded a contract of the answer box, and
narrowed frames by region -- and what fuzzing the new protocol found: the
Part::Of composition dropping a pinned length, and a local redraw that
must be put back in the parent's answer box. The Pad frame rule is left
as a decision for Bryan with its cost stated.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Bryan's decision of 2026-09-18, which answers the Pad question and
makes the code's leftover filter in declared_lens a bug.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A second planning pass over 49cec82: both seeds are the rule that picks
which answer places a box, shown by shrunk trees, a draw trace and two
counter-experiments, with the recommendation they point at.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The plan in this document is now a protocol in the code, on
`wip/transparent-frames` in the layout experiment: what it does, what the
rig measures it at, and the two things it ran into -- what a widget's answer
is the answer to when a container is drawn in two of its own boxes in one
frame, and what `Pad` should be now that a frame passes through. Both are
Bryan's to decide and both are at the top of Next.
The frame/extent prototype's chronicle goes with it: its four findings that
still hold and its two failed hypotheses stay, the rest was a record of how
the code got to a shape it no longer has.
Decided with Bryan on 2026-09-18: a child's frame is forwarded through
spans, stacks and scrolls and narrowed only by what is decided from above,
so rel is never a fraction of a self-sized box; placements are parts of
the parent's extent in frame units from its start, so a moved extent
re-places its children exactly; the placement pin becomes a symbolic
length; and a local redraw asks at the offer placement without deferring.
Lists the steps in order with the check for each and the failures that
mean stop rather than patch.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The experiment's `many` loss against e44dea3 came from `redraw` refusing
any widget whose given frame is not its offer and marking its parent
instead, which under the frame/extent protocol chains to the root because
a span gives its children its own placement across itself as their frame.
Record the trace, the measured bound with the pin off, the local re-ask
branch `wip/local-reask` and its two remaining depth-6 counterexamples,
and point readers at this section before the earlier explanations.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The placement pin was not most of it. Deleting the read prices no dependency
at all; expressing it properly is `e6ba570`, worth 19% of seed 13's `many`
and 20% of `resize`. What refuses most reuses is the extent contract -- 819
of 1,203 refusals a frame -- and that is the measuring ask and the placing
ask being two different extents, which `Span` is the remaining reader of.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The first item on the plan landed as two commits on #18. The re-parenting
half turned out to be two defects rather than the predicted one -- the old
parent's child list erasing a subtree it no longer draws, and the settling
walk ordering by a stale depth -- and the `depth()` assertion the note
expected to catch it catches only the second.
`dirty_size_under` is deleted, so the section that argued for it is marked
superseded rather than removed: it says what the bottom-up walk is buying.
Bryan's ordering replaces the stale-answer check with something the shape
of the frame makes impossible: nothing shallower is drawn while anything
deeper is dirty, so a parent never reads an answer that is about to move.
The other two are written up rather than landed. A stack takes its sizing
child's fraction twice, which no oracle can see because warm and cold are
wrong alike; the fix is three grid steps short of the tolerance. And
padding is to go outside what it pads with an `Inset` beside it, which one
unaccounted halving is holding up. Both are pushed as `wip/` branches.
The two seeds a wider scan found were one defect, older than the branch: a
text reported a width rounded to the step below the line it measured, so
the box that came back to it broke differently. Two tolerances were holding
that together and both are gone.
The `rel` reading Bryan decided landed, and with it a defect the retained
machinery had all along: a span that can overflow itself makes the two asks'
boxes differ far enough that a reused answer is read before the subtree
under it has settled.
Widening the fuzzers to 2000 seeds at depth 4 then found two warm/cold
divergences that predate both commits, so the branch is not correct and the
routine verification does not say otherwise. They lead "Next".
The review's verdict, Bryan's decisions on rel and on the measure/draw
split, the four findings with their measurements, the residual and the
shader snap, and the reordered queue. The chronicle of closed defects,
superseded verification lists and the cross-fixture tables the document
said not to compare are gone; the rules, lessons and current measurements
stay.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A box in pixels is threaded down the draw now rather than composed back up
the move chain, which closes the offer chain breaking at a region node,
makes `Holds::through` an exact preimage, and retires `redraw`'s third ask.
The section that diagnosed the defect becomes the one that states the rule,
with what the plan got wrong recorded beside it: `px` cannot be stored on
`ActiveData`, because a resize that every `Holds` admits redraws nothing and
would leave it stale everywhere.
`AGREE_STEPS` stays 2, measured rather than assumed: one step passes the
100-seed oracle and fails the 400-seed shrinker on `resize-size` by
0.002 px, so the second step belongs to the resize path re-expressing a part
as a fraction of a box that changed length.
The review of that change found an older defect of its own -- a `Masked`
widget settled on its own panicked, since `redraw` handed it its own mask as
the one it inherited -- and the invariant that closes it is here too.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Iris 5b78002 on #18: a child's answer comes back in the asker's frame, the
near-edge override is per-axis decided flags, and the window is no longer
a move entry. Also records the threading plan that closes the region-node
offer defect, and why widening the grid would not.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
It was in 5f16617's message and not here, which is the wrong place for it:
the handoff is what a session picking this up cold reads.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`5f16617` carries the composed box down the draw instead of walking back up
for it, which made exact composition a 3.6%/3.3% speedup rather than a cost.
The numbers are in "Performance" and the i64 item.
And seed 220 is diagnosed rather than left as a seed. `offered_region`
composes a widget's offer through its ancestors' offers except where the
parent is a region node, where it falls back to the node's **placed** box.
`Scroll` is where placed and offered differ -- it offers its content the
viewport and places it in a box as long as the content -- so the offer
becomes a function of the answer being re-derived and the old answer
confirms itself. It is the fourth defect this session to come down to the
offer against the placed box.
The write-up has the trace both ways, the fact that each child order settles
to its own fixed point so the tree is not unsettled, that marking everything
dirty converges warm onto cold, and the coordinate-frame problem that makes
the two plausible fixes awkward -- `offer` is in the parent widget's frame
and `region` in the parent node's, so neither answers "was this placed where
it was offered" alone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`45a7176` composes a box down its move chain on a grid fine enough to round
once instead of once a level. `Holds::through`'s two-route allowance is two
half steps where it was three, and it cost nothing: 1,880M instructions and
755M cycles against 1,908M and 760M, with all twenty-five work counters
identical. What paid for the widening is that a length composes on its own in
half the multiplies both ends of a box need, and that only the fraction needs
the extra room.
The i64 item in "Next" keeps the measurement that redirected it, since
aiming the work at the screen invariant would have been wasted.
One half step further is arithmetically available and not taken: shrinker
seed 220 on `reorder` then diverges warm against cold, by re-breaking a
wrapping text whose reported width moves a `Branch` onto its other subtree.
That is written up under the `Holds::through` invariant with its reduction
command and its ten-widget tree, and it is the next thing to chase.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`d21a215` answers the API question: one widget keeps one length per axis, and
`Wrapper` -- what `WidgetPtr` already was -- is the second widget the second
length needs.
The `i64` composition item is rewritten around a measurement that changes
what it is for. `prelude.wgsl` decodes the raw counts into `f32`, walks the
move chain in floats, and lands every edge on a whole pixel with
`snap_floor`. Checked in the render rather than read off the source: there is
no partially covered column anywhere along `tabs`'s band of rounded rects, so
every box edge is hard, and the two `pad(10)` gaps are exactly ten pixels on
both sides of the truncating multiply. The screen invariant is therefore
already as good as integers allow, and exact composition cannot improve it.
What it can still buy is layout's own decisions -- the `Span` leftover
boundary, the queued clamp crossover, `Holds` validity, warm-against-cold
agreement -- with `Holds::through`'s two-route allowance as the test of
whether it worked.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>