From 7122cdc461ce39b14ad705db34f1adfc5b76a676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20T=C3=B6rcsv=C3=A1ri?= Date: Sun, 9 Aug 2026 14:46:06 +0200 Subject: [PATCH] =?UTF-8?q?Phase=20F=20F2/F3:=20quarantine=20NOT=20deletab?= =?UTF-8?q?le=20=E2=80=94=20the=20lever=20proved=20the=20drop=20is=20load-?= =?UTF-8?q?bearing;=20registry=20keeps=20the=20fact?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Td4ujboGuAw26jvbDQzehj --- .ci-cache-epoch | 2 +- .../features/async/22-absorbing-libcontext.md | 34 +++++++++++++++++ kicad | 2 +- scripts/common/shims/asyncify-scheduler.js | 37 +++++++++++++++---- wxwidgets | 2 +- 5 files changed, 67 insertions(+), 10 deletions(-) diff --git a/.ci-cache-epoch b/.ci-cache-epoch index 8351c19..60d3b2f 100644 --- a/.ci-cache-epoch +++ b/.ci-cache-epoch @@ -1 +1 @@ -14 +15 diff --git a/docs/features/async/22-absorbing-libcontext.md b/docs/features/async/22-absorbing-libcontext.md index a9e3acb..f82b674 100644 --- a/docs/features/async/22-absorbing-libcontext.md +++ b/docs/features/async/22-absorbing-libcontext.md @@ -1186,6 +1186,40 @@ Flake watch: `ngspice-probe` "bg_run streams events live" has now failed twice under full-suite parallel load and passed 4/4 solo both times — a de-flake candidate, not a regression. +### F2/F3 — the quarantine is NOT deletable, and the lever proved exactly why (2026-08-09) + +The deletion was BUILT and MEASURED, not assumed. What was tried: the registry +learned the shim's one private fact — "this fiber's body holds an in-flight +in-place handleSleep park" (`Context::inplace_parks`, fed through +`wxWasmSchedInplaceParkBegin/End` from the handleSleep wrap at park start/end) — +`fiber_enterable()` narrowed on it, a registry-informed refusal was added in +`jump_fcontext` (`jump-refused-inplace`), and the shim's +consume-once/quarantine block was deleted with the lever spec flipped to +assert the new refusal. + +**Measured verdict: scenario 1 (direct mid-park poke) works — refused at C++, +body completes. Scenario 2 (the laundered poke) FAILS on a mechanism the +quarantine was silently covering:** under staged attribution rot the SECOND +coroutine's `return_to` is poisoned toward the parked fiber, so its +YIELD-BACK jumps into it. A C++-level refusal answers with the ghost contract +— which GHOST-RESUMES the yielding coroutine, and it runs to completion +(`phase2` overshoots 1→2). The quarantine's drop-at-finishContextSwitch +leaves the yielding side properly suspended — for a misrouted yield-back, +drop is the only correct recovery a non-invocation-aware layer can make. + +**Deleted the deletion; kept the knowledge.** Landed and kept: the registry's +in-place-park fact + Begin/End plumbing (the fiberStackParks counter now +attributes parks to contexts), the `fiber_transfer` refusal for inplace-parked +targets (the star's real lane, where attribution cannot rot), the +`fiber_enterable` narrowing, and the divergence beacons that now light up the +laundering (`sched-divergence-current/enterable`, `FIBER-SWAP-NONENTERABLE`). +The quarantine block is restored verbatim with a header naming its remaining +duty. **Prerequisite for the real deletion, now precisely named: +registry-authoritative jump attribution** (the gap-3 redesign — libcontext +needs a sched-id→context reverse map so a divergent `old` side is corrected at +the jump instead of poisoning `return_to`). Until then, `fiber-resume-park` +scenario 2 stays pinned on the quarantine beacon — deliberately. + ### Prod-provider smoke (2026-08-08) — done, with one pre-existing red bisected Against the live web stack (playwright-web config, reference backend :3060): diff --git a/kicad b/kicad index 452eb52..6e6cf51 160000 --- a/kicad +++ b/kicad @@ -1 +1 @@ -Subproject commit 452eb5260d8a73c2bd0dff8d2a53ab2c05f116be +Subproject commit 6e6cf51027a5b045629518935d78a7683b43535a diff --git a/scripts/common/shims/asyncify-scheduler.js b/scripts/common/shims/asyncify-scheduler.js index f2b54ec..366f191 100644 --- a/scripts/common/shims/asyncify-scheduler.js +++ b/scripts/common/shims/asyncify-scheduler.js @@ -521,20 +521,28 @@ if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) { if (Asyncify.state !== 0) { return __originalHandleSleep(startAsync); } - // Phase E telemetry (doc 22 §5): count fresh in-place parks that begin - // on a NON-main stack (tool coroutine / scheduler context). Must reach - // ZERO at the flip — until then it measures the remaining doc-19-class - // exposure. Leaf probe into wasm; state is 0 here so no unwind is in + // Phase F (doc 22 §10 F2/F3): report every fresh in-place park to the + // REGISTRY. Begin() returns the owning context id (0 = main stack); + // while recorded, fiber_enterable()/fiber_transfer refuse entering that + // context — the registry-owned replacement for the deleted quarantine. + // Also the Phase E telemetry: fiberStackParks must be 0 at the flip's + // repro gate. Leaf probe into wasm; state is 0 here so no unwind is in // flight yet. + var parkOwnerCtx = 0; try { - if (Module["_wxWasmProbeOnFiberStack"] && Module["_wxWasmProbeOnFiberStack"]()) { - AsyncifyScheduler.inplaceParksOnFiberStack++; - __rec("inplace-park-on-fiber-stack n=" + AsyncifyScheduler.inplaceParksOnFiberStack); + if (Module["_wxWasmSchedInplaceParkBegin"]) { + parkOwnerCtx = Module["_wxWasmSchedInplaceParkBegin"]() | 0; + if (parkOwnerCtx) { + AsyncifyScheduler.inplaceParksOnFiberStack++; + __rec("inplace-park-on-fiber-stack ctx=" + parkOwnerCtx + + " n=" + AsyncifyScheduler.inplaceParksOnFiberStack); + } } } catch (e) { /* probe must never break a park */ } var sleepCtx = { capturedData: null, cleanedUp: false, + parkOwnerCtx: parkOwnerCtx, rootOwned: (typeof Fibers === "undefined") || (!Fibers.__inFiberEntry && !(Asyncify.__wakingOwnerFiber || false)), @@ -544,6 +552,14 @@ if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) { var cleanup = function () { if (sleepCtx.cleanedUp) return; sleepCtx.cleanedUp = true; + if (sleepCtx.parkOwnerCtx) { + try { + if (Module["_wxWasmSchedInplaceParkEnd"]) { + Module["_wxWasmSchedInplaceParkEnd"](sleepCtx.parkOwnerCtx); + } + } catch (e) { /* never break a wake */ } + sleepCtx.parkOwnerCtx = 0; + } var idx = Asyncify.__pendingSleepContexts.indexOf(sleepCtx); if (idx !== -1) Asyncify.__pendingSleepContexts.splice(idx, 1); }; @@ -625,6 +641,13 @@ if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) { // --- stale-fiber-rewind guard (ported from handlesleep.js; semantics // unchanged — these encode the consume-once/quarantine contracts of // docs/features/async/16) + trampoline heal ownership ------------------- + // Phase F F2/F3 (doc 22 §10, 2026-08-09): deletion was built, measured and + // REVERTED. The registry now carries the in-place-park fact + // (wxWasmSchedInplaceParkBegin/End) and refuses on the transfer lane, but + // the quarantine's DROP is still the only correct recovery for a misrouted + // yield-back under attribution rot (a C++-level refusal ghost-resumes the + // yielding coroutine — measured as the lever's phase2 overshoot). This + // block stays until attribution is registry-authoritative (gap 3). if (typeof Fibers !== "undefined" && typeof Fibers.finishContextSwitch === "function" && !Fibers.__staleRewindGuardInstalled) { diff --git a/wxwidgets b/wxwidgets index a8d9ece..68787c1 160000 --- a/wxwidgets +++ b/wxwidgets @@ -1 +1 @@ -Subproject commit a8d9ece31f9130dc5b8726924fd2f6f34f1b305f +Subproject commit 68787c1f4418998504a7d0f3b806a494f0c8d109