Adapted from codex/asyncify-execution-owner-core 3753320 (scheduler-free on
that branch already; one comment line re-worded for the JSPI line):
- E-1: generation-slotted WorkerSlot with a 2-min boot watchdog (armed before
resolveWasmBase, so a hung delivery lookup expires too) and a 30-min
per-request response watchdog; retireWorker() is the single idempotent
funnel (fail that generation's pendings, terminate, revoke the worker Blob
URL, clear timers/listeners).
- E-2: worker.onerror is wired for the worker's whole life and settles every
in-flight STEP/export request; a synchronous postMessage throw settles its
request without leaking the pending id; late frames from a retired
generation are inert.
- E-3: worker.onmessageerror retires the generation like error does.
- E-4: collectBoardModelFiles is a pure source/IDB/network path (no editor
MEMFS round-trip) taking an AbortSignal checked at every loop head;
prefetchBoardModels races it against a 30 s deadline — timeout is non-fatal
(export proceeds without models) and late results are inert.
Tests: occ-service.test.ts (7, ported) — boot/response watchdog expiry,
crash-settles-all, bootError retry, decode-fault retirement (invokes the real
onmessageerror transition, per J-4), hung-prefetch export; models-bridge.test.ts
+3 — abort inertness, zero FS access on the collect path. e2e harness twin
updated to the same generation shape (adds __occServiceTestHooks/failDecode).
False-green audited: 19 cases fail with the fixes reverted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>