docs: doc 22 (absorb libcontext) + honest scoreboard on doc 20

Doc 20 gets a status table instead of a narrative: D-1/D0/D1 done, D2
reverted, D3's goal met but its MEANS skipped (waits still park in
place — only the stack they park on changed), D4/D5/D6 not started. Plus
an explicit "what was skipped and is still owed" list, so nothing quietly
reads as delivered: dispatch contexts, waits-as-yields, bridges,
real-park-site buffer sizing, the both-EH CI matrix.

Doc 22 is the handoff plan a fresh session can implement from:
- the bug it targets is the BLUE SCREEN (a context recovered twice or by
  the wrong fiber), not doc 19's hang, which is fixed and was only one
  ingredient;
- the diagnosis that matters: bookkeeping is already centralised
  (currData is single-writer, the shim sees every swap) but the DECISION
  is not — libcontext decides swaps and never tells anyone, so three
  layers each invented heuristics. Centralising means moving the
  decision;
- why D2/D3 knotted, with the measurements, so nobody retries that order;
- phases A-F with estimates (~4-6 wk): A absorbs libcontext behaviour-
  preservingly and is landable ALONE (the de-risking step D2 never had),
  B+C+D must land as one commit, E bridges, F deletes the guards only
  once they are provably silent;
- gates including the crash's own repro, since the batteries never
  reproduced it and therefore cannot certify it;
- the traps this run paid for: 16-byte fiber stack alignment, the
  per-fiber stack-limits gotcha, host-side asyncify buffers, the
  stack-ownership rule, partial migration, and the gitignored-artifact
  triage trick;
- measured build/test cycle costs, so the estimates are grounded.

README: index rows for 21 and 22, doc 19 marked FIXED, and the stale
2026-06 "single decisive next step" folded away behind the current one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEHGiiXMShNXbBr7gSJ7iz
This commit is contained in:
Gergő Törcsvári 2026-08-06 13:47:36 +02:00
commit 23c636dced
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
3 changed files with 290 additions and 15 deletions

View file

@ -44,11 +44,21 @@ or **hang** (a swap unwinds but is never rewound).
| [`09-dom-window-lifetime-hypothesis.md`](09-dom-window-lifetime-hypothesis.md) | Concrete failure story and first fix experiment for the DOM-port stale `wxWindow` hypothesis: destructor ordering, DOM event reentry, and validation plan. |
| [`10-resolution-menubar-uaf.md`](10-resolution-menubar-uaf.md) | **RESOLVED:** the regression was a freed `wxMenuBar` left in a live frame's child list by `wxMenuBarBase::Detach()` (DOM-port only — the bar is a real child there). One-line fix in `wxMenuBar::Detach()`; full kicad suite green, zero corruption signatures. |
| [`11-asyncify-nesting-raytracer.md`](11-asyncify-nesting-raytracer.md) | **Finding + decision:** the WASM 3D raytracer is single-core because `emscripten_sleep` can't nest on an already-unwinding Asyncify context — yielding to join worker threads aborts with `invalid state: 1` since the viewer renders inside a suspended wx modal pump. Multi-core pool (~67×) built + parked; unpark needs a *nestable* yield (fiber/JSPI). |
| [`19-quasimodal-fiber-strand.md`](19-quasimodal-fiber-strand.md) | **DIAGNOSED 2026-08:** the Symbol Properties dialog hang — a tool fiber parks mid-body, the stale-fiber guard refuses (and drops) its resume, the dispatch interlock is never released, every click is deferred forever. Live-captured frozen state; ranked fixes; regression-vs-pre-existing still open. |
| [`20-design-b-core-plan.md`](20-design-b-core-plan.md) | **PLAN (2026-08):** the remaining Design B core — every parkable activity becomes a scheduler context that yields instead of parking in place, which deletes the guessing layer (quarantine/consume-once/interlock) rather than tuning it. Phases D0D6, 610 wk, with the memory and partial-migration risks called out. |
| [`19-quasimodal-fiber-strand.md`](19-quasimodal-fiber-strand.md) | **FIXED 2026-08-06:** the Symbol Properties dialog hang — a tool fiber parked mid-body, the stale-fiber guard refused (and dropped) its resume, the dispatch interlock was never released. Cure: a quasi-modal's nested loop no longer parks on a coroutine stack. Regression pin: `tests/kicad/quasimodal-strand.spec.ts`. Note this removed one INGREDIENT, not the blue-screen cause. |
| [`20-design-b-core-plan.md`](20-design-b-core-plan.md) | **PARTIALLY DELIVERED 2026-08:** Design B core. D-1 (legacy runtime deleted), D0 (park-site audit + red spec) and D1 (context primitives + memory gate) landed; D2 (dispatch contexts) was reverted; D3 met its goal by other means. Read §10's work log for what each phase actually cost. **Superseded for the remaining work by 22.** |
| [`21-park-site-audit.md`](21-park-site-audit.md) | **AUDIT 2026-08:** every Asyncify park site classified by whose stack it suspends (tool fiber / entry stack / main loop) with its routing phase — 14 production sites + 3 test levers. Settles the pthread question: all parks are main-thread; the lib bridge's worker path is a blocking proxy, not a park. |
| [`22-absorbing-libcontext.md`](22-absorbing-libcontext.md) | **PLAN (2026-08-06), the current one:** absorb libcontext's wasm backend into the scheduler so ONE handler owns every js↔asyncify↔fiber switch — the cure for the blue screen (a context recovered twice or by the wrong fiber). Diagnosis of why three guard layers cannot fix it, why the D2/D3 phases knotted, phases AF with estimates (~46 wk), gates, and the traps this implementation run paid for. **Start here.** |
| [`17-mailbox-scheduler-plan.md`](17-mailbox-scheduler-plan.md) | **PLAN (2026-08):** the mailbox/scheduler implementation plan — Design B's phasing revised with the JulyAugust guard record (dispatch interlock, open-settle gate, v0.1.28 schedule-don't-dispatch). Test inventory with per-test fate (keep / rewrite / retire / new), 7 steps S0S6 with gates and rollback, ≈57 wk. Supersedes 12/13's phasing; overturns 13 §6f's "no scheduler needed". |
## The single decisive next step
## Where to start (2026-08-06)
**Read [`22-absorbing-libcontext.md`](22-absorbing-libcontext.md).** It carries the current
plan, the diagnosis behind it, and the traps the last implementation run paid for.
Prerequisites: [`20`](20-design-b-core-plan.md) §10 (what each phase actually cost) and
[`21`](21-park-site-audit.md) (the migration surface).
<details>
<summary>The original "single decisive next step" (2026-06, answered)</summary>
Before designing anything, **measure whether `Asyncify.currData` is clean (null) at the moment
`wxGUIEventLoop::DoRun()` throws `"unwind"`** (and at the first rAF tick, and at the first
@ -56,6 +66,8 @@ post-startup `emscripten_fiber_swap`). That one fact determines whether the univ
also reshape the main loop ("de-parking") or whether a per-context `currData` authority alone
suffices. Details in [`04-decisions-tests-open-questions.md`](04-decisions-tests-open-questions.md).
</details>
---
## RESOLUTION (2026-06-12) — see [`07-decisions-and-outcome.md`](07-decisions-and-outcome.md) and `docs/features/asyncify-arbiter/`