fix(asyncify): ownership-scoped root deferral — the recorded nested self-rewind, cured

The v0.1.23 flight recorder caught the kill live (console-export-2026-8-1_19-16-8):
dozens of benign fiber round-trips at w=0, the yield cycling healthily on its
buffer — then "fcs … ROOT w=1" and the trap, state frozen at Rewinding with
currData=root+20. The fatal condition, observed rather than inferred: a fiber
round-trip inside the ROOT's OWN sleep-wake continuation re-suspends and
re-rewinds the root nested inside its live wake rewind. Consume-once passed
correctly — it guards a different corruption and stays.

The round-3 deferral was aimed right but unscoped (taxed fiber-owned wakes,
flaked S4). Final form: every fresh sleep is tagged root- or fiber-owned
(fiber ⇔ started inside a finishContextSwitch fiber slice or a fiber-owned
wake; root entries don't count as slices); finishContextSwitch(root) defers
one macrotask ONLY while a root-owned wake is live (Asyncify.__wakingRoot).
Beacon: root-entry-deferred. Verified inert where it must be: zero beacons
across all 13 drift-trio-scenarios logs (26/26 + 25/26-then-26/26 stress —
the single miss carried no beacons, i.e. the pre-existing under-load flake).

Also: resume re-entries no longer push sleep contexts (the v0.1.23 dump
carried ~380 leaked zero-linked entries), and wake events in the recorder are
tagged R/f for ownership.

.ci-cache-epoch 5→6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019SE4o46Lnq3hF574FFq8x4
This commit is contained in:
Gergő Törcsvári 2026-08-01 19:49:38 +02:00
commit 210b079ed9
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
3 changed files with 94 additions and 4 deletions

View file

@ -159,6 +159,29 @@ installed at module import in main.tsx, cooperating with the React overlay
moment it disappears — 1 Hz ensure-loop). `fatal-overlay.spec.ts` now also
kills the React root after the fatal and asserts the DOM floor appears.
## Round 4 (2026-08-01 evening) — the recorder caught it: nested self-rewind of the root
v0.1.23 still trapped, but this time with the black box
(console-export-2026-8-1_19-16-8): dozens of benign fiber round-trips at
`w=0`, the yield cycling healthily — then `fcs old=root new=88145920 w=1` /
`fcs … ROOT w=1` and the trap, with the state dump frozen at
`state=2 currData=root+20`. The fatal condition, now OBSERVED rather than
inferred: a fiber round-trip executed inside the ROOT'S OWN sleep-wake
continuation re-suspends and re-rewinds the root nested inside its live wake
rewind — two rewind lifetimes on one context. Consume-once passed correctly
(the suspension was fresh); it guards a different corruption.
The retracted round-3 deferral was aimed right but unscoped: benign
parked-fiber completions run in FIBER-owned wake windows (or at w=0) and
must not pay the hop (that tax flaked S4). **Final form: ownership-scoped
deferral.** Every fresh sleep is tagged root- or fiber-owned (fiber ⇔
started inside a `finishContextSwitch` fiber slice or a fiber-owned wake);
`finishContextSwitch(root)` defers one macrotask ONLY while a ROOT-owned
wake is live (`Asyncify.__wakingRoot`), with the
`root-entry-deferred` beacon. Also fixed: the resume re-entry no longer
pushes sleep contexts (the v0.1.23 dump carried ~380 leaked zero-linked
entries).
## Flight recorder (round 3, targeting instrument)
The shim keeps a 96-entry ring of asyncify/fiber events (sleep entries with