The local fix left `origin/main` at the app's line, so a fresh clone of the
fork -- which has no `upstream` remote -- still resolved `main` to the wrong
base. Force-pushed to `ca2b4b2` with `origin/HEAD` following it; the app's
45 commits stay reachable through `app-pin`, which was pushed first.
Verified by cloning the fork: `git merge-base main <branch>` gives ca2b4b2
with only `origin` configured, the parley migration no longer appears in the
diff, and the pinned `32f6ad8` is still present.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The `iris` submodule's `main` was the fork's own line -- the app's 45
commits -- and not an ancestor of upstream's main, so it sat four merged
pull requests behind PR #19's actual base. Every obvious command was
therefore wrong in a way that looked plausible: `git diff main...` showed
#10, #12, #16 and #17 as the review branch's work, which is how the parley
text migration's undo path kept being reported as #19's.
The app's line is now `app-pin`, pushed to origin, and `main` tracks
`upstream/main`. `.gitmodules` follows `app-pin`, so `submodule update
--remote` cannot drag the pin onto upstream. The recorded commit is
unchanged at 32f6ad8; only the name it is reachable by has changed.
`origin/main` on the fork is left alone: moving it is a non-fast-forward on
a shared branch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR #19's base is upstream/main at ca2b4b2, not the local `main`, which
tracks the fork's divergent line and sits four merged pull requests behind
it. Diffing against `main` shows #10, #12, #16 and #17 as this branch's
work; that is how the parley text migration's undo path kept surfacing in
sweeps. Git cannot record a pull request's base and `main` cannot be
renamed, so the handoff carries the note and the checkout carries
`git iris-base`/`git iris-diff`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`pre-submit-review` arrived after the Rust port and most of Iris were
written, so all of that went in unreviewed and no sweep has covered it. The
surface-texture defect is the argument for a pass of its own.
Nothing in Iris is kept for the app's sake either: the app is to be rewritten
against the new API rather than ported call by call.
The handoff said "three rounds" over four bullets and carried the detail of
each, which belongs in the findings log. It now names the four and their
commit ranges and points at `LAYOUT_LOG.md`, which gains the naming and
sweep round in full.
The check section split in two: the cheap gate runs on every change
including a rename, because the cold dump is the only thing that catches two
same-typed values being swapped; the seed scans run only when the change can
alter what layout computes, and never with the tree still moving under them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Iris PR #19's tip is 2807a92. LAYOUT.md's settled-design section named the
retired `PlaceDescAxis::within`/`shifted`/`sized` constructors and the
`axis`/`axis_mut` accessors; it now says the `_desc` chaining rule, the
`axis` lift, and that every pair is a struct of two per-axis values read
with `[axis]`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The handoff had grown a chronicle of what each commit renamed. What is
durable about it -- the three names, and the one argument a container uses
to say them -- is design, so it goes to `docs/LAYOUT.md` as its own section
and the handoff keeps a pointer plus where the branch stands.
`docs/PLAN.md`'s "frame/extent experiment" entry described a prototype in
retired words; it becomes a pointer, and the one finding it held that was
not recorded elsewhere -- why the extent-relative child-frame trial was
removed -- joins the failed hypotheses in `docs/LAYOUT.md`.
`frame` is gone from the layout vocabulary in `docs/LAYOUT.md` too, since
leaving the design document in the old words defeats the rename; the
rendered-frame sense of the word is untouched. The `local == UiRegion::FULL`
item is dropped from the handoff: that comment was #18's and is not on the
review branch.
The `extent` rename landed as iris `5642f20`; the handoff had not listed it
as pending at all, and its item 2 named renames that are already upstream.
Say which vocabulary the app has still to absorb, drop the retired-clone
and archive chronicle, and strike the three clarity findings now done.
Two live defects at cadfba0, each with the repro that showed it and the
fix that answered it: a span places the slot after a collapsed leftover
child a gap early and a gap too long, and a child reused under a parent
that redrew keeps the mask index that parent replaced, so its drawing is
clipped where the subtree used to be. Neither is covered by a test, which
is why the suite is green over both.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`docs/LAYOUT_LOG.md` existed until the one-ask protocol landed. It has, as
Iris PR #19 replacing #18, so what has to outlive the log moves into
`docs/LAYOUT.md`: the hint rule and the one ask a span makes, the reported
shares that are left and the two-answers design that would remove them, what
the fuzzers reach and what they cannot, the hypotheses not to repeat, and the
counter and dump commands with the numbers they print now. The handoff becomes
what it is for -- where the work stands, which is waiting on a review.
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>