Skip to content

Consolidate the mutation rebuild path - #46

Merged
brainkim merged 1 commit into
mainfrom
rebuild-consolidation
Aug 16, 2026
Merged

Consolidate the mutation rebuild path#46
brainkim merged 1 commit into
mainfrom
rebuild-consolidation

Conversation

@brainkim

Copy link
Copy Markdown
Member

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

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>
@brainkim
brainkim merged commit 135e362 into main Aug 16, 2026
2 checks passed
@brainkim
brainkim deleted the rebuild-consolidation branch August 16, 2026 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant