Parents: #474, #482 Related: #480, #493, #885, #886, #887, #896
Source-level ownership finding
At 9fb57fa01035d7e5712f9283972cb92c48c26bef, both waitAsync completion paths remove their last completion record before a fallible Promise resolution whose error is discarded:
- Property-mode
settlePropAsynccallspromise.resolve(... ) catch {}after notify/expiry has detached its ticket fromg.prop_async, then unconditionally frees the ticket/key. Queue routing is protected against Thread exit, but root registration and settlement publication can still fail. - Shared-buffer
Interpreter.settleAsyncWaitersharvests the native outcome, removes the matching entry withtakeAsyncWaiter, callspromise.resolve(... ) catch {}, and finally abandons/clears remaining native/context waiter state.
Consequently, an allocation failure at completion can discard the sole notification/timeout outcome while leaving the already-exposed Promise pending. #885 makes an individual Promise publication transactional, but these callers currently discard the operation that would retry or complete that transaction. #896 owns reporting of unowned host-checkpoint errors; reporting alone cannot restore a destroyed waiter ticket.
This is a source audit, not yet a deterministic failing-allocator measurement.
Required implementation
- Give each admitted asynchronous waiter an exact completion/publication owner before exposing its result Promise.
- Preserve the harvested outcome and a precise, relocatable Promise root until resolution/rejection and required reaction publication commit. Do not free/drop the ticket or consume the last native outcome first.
- Evaluate reuse of #887's prepared settlement API, preserving the existing queue affinity, notify/timeout ordering, and worker-to-realm queue handoff from #886.
- Make admission failure, not-equal/immediate-timeout paths, notify/expiry races, completion, cancellation, and Context/Thread teardown release each token/root/ticket exactly once.
- Preserve lock order across agent state, property waiters, Thread completion, queues, and Promise state. Do not resolve allocating work under a lock that GC/recovery must reacquire.
- No swallowed OOM, permanently pending orphan, duplicated outcome, callback replay, arbitrary waiter cap, emergency allocation pool, or global serialization.
Acceptance
- Deterministic fault witnesses cover property and shared-buffer waitAsync, notify and timeout, empty/full destination queues, and multiple harvested outcomes (including the fixed harvest-buffer boundary).
- Every failure proves exact native/context ticket membership, Promise state, reaction ownership, queue ordering, and eventual once-only completion after recovery.
- Moving/concurrent GC and bounded-heap recovery retain and rewrite detached completion roots through publication.
- No-GIL notify/timeout/Thread-exit races, teardown, relevant corpus cases, threadfuzz, full units, suppression-free TSan, and affected Test262/private ABI checks pass.
Security scope
Waiter fanout and memory pressure are script-controlled. This is engine state integrity under resource exhaustion, without adding an embedding sandbox or permission layer.