Parent: #480 Related: #474, #495, #885, #886, #887
Observed boundary
While implementing #885's job-execution OOM ownership, a native fault callback resolved its thenable target to another queued thenable, then returned error.OutOfMemory. The direct Interpreter.drainMicrotasks witness observes the abrupt engine error and retains the committed adoption job for exact recovery. Calling through Context.evaluate instead returned success: the host checkpoint catches and discards the error, then another checkpoint can run the retained suffix before the host sees any failure.
Source audit at 9fb57fa01035d7e5712f9283972cb92c48c26bef:
Context.evaluateusesmachine.drainMicrotasks() catch {}anddrainFinalizationCleanupJobs() catch {}around waiter handling and again after Thread completion.- Module evaluation has the same unconditional checkpoint catches.
- The underlying queue transaction in #886 preserves untouched work; these host catches are a distinct error-reporting boundary.
This is an observed synthetic native OOM plus a source audit, not a measured heap-budget exhaustiveness claim. The current #885 implementation converts failures owned by an intrinsic Promise into committed rejection; those successfully delivered rejection outcomes must remain distinct from an unowned checkpoint failure.
Required implementation
- Define and implement the host-facing result of engine OOM during script/module checkpoints, finalization cleanup, waiter completion, and post-Thread cleanup.
- Preserve the original script/module abrupt completion when cleanup also fails; do not replace a rooted primary exception with a secondary checkpoint error.
- Report unowned engine failure through the existing Zig/public C/private ABI error channels appropriate to each pinned contract, without changing exported layouts or conflating ordinary JS job exceptions with an evaluation exception.
- Keep successfully committed Promise rejection as rejection, and preserve the exact untouched queue suffix and GC roots until authorized later execution or teardown.
- Audit the repeated checkpoints so secondary drains cannot silently consume the failure boundary. Never replay an already-run callback, clear a pending queue to recover, or add a retry loop that hides allocator failure.
Acceptance
- Deterministic allocator/native-fault witnesses distinguish top-level success + checkpoint OOM, top-level throw + cleanup OOM, ordinary JS job throw, and a successfully committed OOM Promise rejection.
- Script and module entry points agree on documented error ownership; original exception identity survives moving/concurrent GC and post-Thread cleanup.
- Recovery preserves FIFO/exactly-once callback execution and retained adoption work in direct, nested, and host checkpoints.
- Focused Debug/ReleaseSafe/suppression-free TSan, public/private ABI fixtures, relevant async/thread integration, full units, and affected Test262 diagnostics pass.
Security scope
This is a bounded-heap/embedding error-integrity boundary. The engine must preserve state and report failure accurately under script-controlled allocation pressure; it does not add a sandbox or permission layer.