Consolidate the mutation rebuild path - #46
Merged
Merged
Conversation
A container's enumeration is the only thing that says which boxes it holds, and the one path that builds a box is the only thing that builds one. Reconciliation runs that path over every box the enumeration names, so a box reached by mutation is made of what a fresh build would have made it of: its kind, the styles on it, the content root under it, and the boxes it holds in turn. An element that stops laying out boxes of its own gives them up -- a run measures everything inside it as one unit, so nothing in there owns a layout node, and the out-of-flow box that left for its containing block is hoisted rather than retired. The enumeration names those boxes too, which is how the derivation reaches them at all. A box's position is read out of the run that placed it, never out of a run inside it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes six shipped bugs found by the fuzzing campaign — five as consequences of one architectural change, one crash with a guard.
The diagnosis: the engine's doctrine is mutations-mark-one-path-rebuilds, but the rebuild was partial — fact-specific restaging sites each re-derived some facts (box kind on restyle, but not on child-list change; styles, but not auto-margin solves; nothing at all for out-of-flow boxes inside inline runs). Every derived fact a site didn't cover went stale, each escape wearing a different costume.
The change: #applyRestyles and #restageForRecord become pure marking; #syncContainerRuns runs the fresh build's own #addNode over every box the enumeration names; and the enumeration now names out-of-flow boxes — previously invisible when inline-level, which is why an element becoming position:fixed at runtime (style write or the popover attribute) was never hoisted and solved its auto margins against body instead of the viewport. Run-content and run-member derivation are stated once as invariants (#retireRunContent, #syncRunMembers) instead of scattered as responses.
Fixed, each with a regression test that fails on main: runtime position:fixed/popover pinning to row 0 (two routes); a flex item painting nothing after its inline child stops holding a block; display:contents in an inline dropping the subtree; an order-dependent two-frame contents+white-space divergence; a ::before that incremental and fresh disagreed about; and a process-killing infinite climb when an inline moves into a block inside an inline-block — the loop closed through a run head that had moved inside the box being resolved, and the guard states the invariant (the climb only accepts a head outside the element), which also closes the host search. Plus one novel scenario the campaign never found — a run member leaving the flow — as evidence the consolidation generalizes.
Net +38 lines in layout.ts: the fact-specific responses collapsed, and the derivations they approximated are now real named code with documented invariants. No new caches or validity levers; the frozen fuzz net passes unmodified.
Full suite: node 1249/0, bun 1274/0, exit 0.
Interlock note: PR #45 (grid) carries twelve mutation-path tests written for exactly this change; whichever merges second gets rebased and both suites run together.
🤖 Generated with Claude Code
https://claude.ai/code/session_01C8sSHf9EvBZroVnsXJbJSD