fix(asyncify): retire the deferral family — guard-layer road closed
v0.1.24 in prod, doubly convicted the same morning: the Leonardo open crawled/hung (open:settled result=failed at the 60s escape, heap never past 256MB — every main-loop iteration runs INSIDE its yield-wake extent, so the "root-owned wake" scope matched thousands of legitimate nested coroutine Call/returns per open, each paying a deferred macrotask, throttled to ≥1s in a background tab), AND the Nano crashed 22ms after deferrals=1 fired. Harmful and insufficient: the fatal nested-rewind interleave and the benign bulk are observationally identical at this layer — no discriminator exists. Retired (second and final retraction, async/16 round 5). What stays shipped and clean: consume-once root suspensions, the internally-parked quarantine + laundering check, the flight recorder + beacons, the WSOD floor, the pendingSleeps leak fix (confirmed by pendingSleeps=[] in the Nano dump). The rare nested-rewind crash is ACCEPTED and fully observable until the structural fix — the design-B fiber-first runtime (async/06,12,13), where one scheduler owns every suspension and this interleave cannot exist. .ci-cache-epoch 6→7. Local: fiber 2/2 (one refusal beacon) + timer + firefox sweep 21 passed, chromium scenarios 11 passed/4 quarantine-skips, web fatal+follow 2/2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019SE4o46Lnq3hF574FFq8x4
This commit is contained in:
parent
1b84b77c8d
commit
f734d700a2
3 changed files with 37 additions and 31 deletions
|
|
@ -1 +1 @@
|
||||||
6
|
7
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,30 @@ wake is live (`Asyncify.__wakingRoot`), with the
|
||||||
pushes sleep contexts (the v0.1.23 dump carried ~380 leaked zero-linked
|
pushes sleep contexts (the v0.1.23 dump carried ~380 leaked zero-linked
|
||||||
entries).
|
entries).
|
||||||
|
|
||||||
|
## Round 5 (2026-08-02) — the scoped deferral hangs opens: RETIRED, road closed
|
||||||
|
|
||||||
|
v0.1.24 in prod: `open:settled result=failed` at the 60 s escape, heap never
|
||||||
|
past 256 MB, no traps, no beacons — the open crawled and (in a
|
||||||
|
timer-throttled background tab) effectively hung. Cause: the main loop's
|
||||||
|
every iteration runs INSIDE its yield-wake's synchronous extent (the v0.1.23
|
||||||
|
recording shows `sleep … w=1` on every tick), so "root re-entry during a
|
||||||
|
root-owned wake" matches every legitimate nested coroutine Call/return in a
|
||||||
|
board open — thousands per load, each paying a deferred macrotask.
|
||||||
|
|
||||||
|
**Verdict on the whole deferral family:** the fatal nested-rewind interleave
|
||||||
|
and the benign nested round-trips share the same observable signature at the
|
||||||
|
JS runtime layer. No discriminator exists here — this road is closed. What
|
||||||
|
remains shipped and sound: the consume-once validity + internally-parked
|
||||||
|
quarantine (never implicated in a regression), the flight recorder, the
|
||||||
|
beacons, and the WSOD floor. The rare nested-rewind crash is ACCEPTED, fully
|
||||||
|
observable, until the structural fix.
|
||||||
|
|
||||||
|
**The structural fix is design B** (06/12/13-design-b-*): one fiber-first
|
||||||
|
scheduler owning every suspension, so dual-protocol nesting cannot exist.
|
||||||
|
That is the next real investment; guard-layer iteration has hit its ceiling
|
||||||
|
— five variants, each defeated by a neighboring interleave or by taxing the
|
||||||
|
benign bulk.
|
||||||
|
|
||||||
## Flight recorder (round 3, targeting instrument)
|
## Flight recorder (round 3, targeting instrument)
|
||||||
|
|
||||||
The shim keeps a 96-entry ring of asyncify/fiber events (sleep entries with
|
The shim keeps a 96-entry ring of asyncify/fiber events (sleep entries with
|
||||||
|
|
|
||||||
|
|
@ -323,36 +323,18 @@ if (typeof Fibers !== "undefined"
|
||||||
|
|
||||||
var isRoot = newFiber === Fibers.__rootFiber;
|
var isRoot = newFiber === Fibers.__rootFiber;
|
||||||
|
|
||||||
// THE prod killer, finally recorded by the flight recorder (v0.1.23 dump,
|
// DEFERRAL RETIRED (2026-08-02, second retraction — see async/16 round 5).
|
||||||
// event "fcs … ROOT w=1" immediately before the trap): a fiber round-trip
|
// Both deferral variants are unsound: the main loop's every iteration runs
|
||||||
// executed inside the ROOT's OWN sleep-wake continuation re-suspends and
|
// INSIDE its yield-wake's synchronous extent, so "root re-entry during a
|
||||||
// re-rewinds the root NESTED inside its live wake rewind — two rewind
|
// root-owned wake" also matches every legit nested coroutine Call/return
|
||||||
// lifetimes on one context; asyncify dies with state stuck at Rewinding.
|
// in a board open — v0.1.24 deferred thousands of them per load and the
|
||||||
// Fiber-owned wakes completing into root are the benign bulk (the same
|
// open crawled/hung (open:settled result=failed at the 60s escape,
|
||||||
// recording shows dozens at w=0 / fiber-owned) and are NOT deferred —
|
// "hung forever" with a throttled background tab). The fatal interleave
|
||||||
// that unscoped deferral was the retracted S4-flaking version. Only a
|
// and the benign bulk share the same observable signature at this layer;
|
||||||
// root re-entry during a ROOT-OWNED wake defers, one macrotask, so the
|
// the discriminator does not exist here. The rare nested-rewind crash is
|
||||||
// outer rewind fully settles first.
|
// accepted until the fiber-first runtime (design B) removes the dual
|
||||||
if (isRoot && (Asyncify.__wakingRoot || 0) > 0) {
|
// suspension protocols altogether; the recorder keeps every occurrence
|
||||||
var deferred = newFiber;
|
// fully observable.
|
||||||
Fibers.__rootDeferrals = (Fibers.__rootDeferrals || 0) + 1;
|
|
||||||
if (Fibers.__rootDeferrals <= 10 || Fibers.__rootDeferrals % 100 === 0) {
|
|
||||||
console.warn("[wx-asyncify] root-entry-deferred: fiber completion inside the root's own "
|
|
||||||
+ "wake window; retrying next tick (occurrence " + Fibers.__rootDeferrals + ")");
|
|
||||||
}
|
|
||||||
__fcsRec("defer ROOT-self new=" + deferred);
|
|
||||||
var retry = function() {
|
|
||||||
if (Fibers.trampolineRunning || Fibers.nextFiber) {
|
|
||||||
setTimeout(retry, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
__fcsRec("defer-retry new=" + deferred);
|
|
||||||
Fibers.nextFiber = deferred;
|
|
||||||
Fibers.trampoline();
|
|
||||||
};
|
|
||||||
setTimeout(retry, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var HEAPU32v = (typeof GROWABLE_HEAP_U32 === "function") ? GROWABLE_HEAP_U32() : HEAPU32;
|
var HEAPU32v = (typeof GROWABLE_HEAP_U32 === "function") ? GROWABLE_HEAP_U32() : HEAPU32;
|
||||||
var entryPoint = HEAPU32v[((newFiber + 12) >>> 2) >>> 0];
|
var entryPoint = HEAPU32v[((newFiber + 12) >>> 2) >>> 0];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue