Skip to content

#106: park-scoped state discharges on every settle path - #112

Merged
lann merged 1 commit into
mainfrom
parks-106
Aug 11, 2026
Merged

#106: park-scoped state discharges on every settle path#112
lann merged 1 commit into
mainfrom
parks-106

Conversation

@lann

@lann lann commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

What

Closes #106 — the cleanup-only-in-produce siblings of #102. Every enumerated site now discharges its park-scoped state on EVERY settle path (produce-success / produce-throw / abandon) via SuspensionPoint.onSettled, or carries the amendment-2 exemption argument the issue asked for:

  1. SITE 4 lit (stream_builtins.ts sync copy park): end.hasSyncWaiter — clear kept in produce (ordering pinned), idempotent onSettled backstop added. Without it an abandoned park left the flag set forever and a later cancel-copy / Waitable.drop trapped against a waiter that no longer existed.
  2. SITE 2 lit (async_builtins.ts waitable-set.wait park): wset.numWaiting -= 1 MOVED from produce to onSettled — the decrement is not idempotent, so the hook is its sole owner; it now runs exactly once on normal resume, cancelled resume, produce-throw, and abandon (the comment's old "exactly once" claim was false for abandon, as the issue noted). Nothing can observe the still-elevated count between produce and the hook (both run synchronously inside the settle).
  3. SITE 5 lit (async_builtins.ts sync subtask.cancel park): same treatment as SITE 4.
  4. Sync host-import park (exec/boundary.ts): settle-path enumeration written at the site. produce-throw is exempt-by-poisoning under amendment 2 — the analysis the issue asked to have written down: every rejection reaching this park is a poisoning trap in the caller's own frame (the conventions layer resolves branded WitErrors on fallible imports into err-shaped VALUES before this boundary — embedder/instantiate.ts #wrapImportFn; every other conventions throw is a Trap; raw-executor rejections are declared host bugs, empirical fact (e); no capability signal can originate inside produce since the park exists only once jspi + suspending() were granted). abandon is NOT exempt (fact_calls: sync-start JSPI park releases lenders only in produce() — cancel/error settle paths can strand them #102 pins an abandoned park as non-poisoning), so the park gets onSettled: () => subtask.unwindLenders() — no-op on success (resolution already delivered), the fix for abandon, belt-and-braces on the poisoned produce-throw leg.
  5. Found during the closure (same class, same lowering): the needsJspi bail in createLoweredImport fires AFTER onStart lifted borrows into the subtask — a capability signal is expressly non-poisoning (amendment 2, fact_calls: lender scopes leak on trap/NeedsJspi in start-call paths; sync post-return leg lacks unwind #91 scope clarification) and must not strand lenders. subtask.unwindLenders() now precedes the bail.

Mechanically: Subtask.unwindLenders() is the #91 never-delivered unwind promoted from a module-private helper in fact_calls.ts to a Subtask method (fact_calls' unwindSubtaskLenders is now a thin alias); idempotent and delivery-aware, so hooks can call it unconditionally.

Tests

runtime/tests/park_state_settle_test.ts (9 tests, the resource_lender_park_settle_test.ts scaffolding): per-site abandon discharge with the trap-observable pinned (waitable-set.drop / cancel-copy / resource.drop staying legal on a non-poisoned caller), decrement-exactly-once on the cancelled-resume and produce-throw legs, host-import success-path no-double-release, rejection-leg belt-and-braces unwind, and the NeedsJspi-strands-lenders pin.

Mutation check: with runtime/src reverted, 6 of 9 go red — exactly the six defect paths; the three that stay green are the paths that were already correct pre-fix.

Gates

  • just test-runtime — 484 passed / 0 failed (incl. the 9 new)
  • just sched-seeds — 484/0 under DELTIC_SCHED_SEED=1 and =4242; seeded conformance 69 files / 0 failed
  • just conformance — TOTAL 1395 commands, 1349 executed, 1254 passed, 0 failed, 95 xfail (no stale)
  • just test-wasi-shims 52/0 · just test-ct-runner 22/0 · just test-ports 12/0

Exposure note (unchanged from the issue): sites 1–3 and the host-import abandon leg are latent until a teardown path calls abandon() — this closes the class before that lands. The needsJspi-bail leg (5) is live today on any non-jspi/unmarked sync import that returns a Promise while borrows are lent.

@lann
lann enabled auto-merge August 11, 2026 21:47
@lann
lann merged commit 7c64f1c into main Aug 11, 2026
4 checks passed
@lannbot
lannbot deleted the parks-106 branch August 23, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

parks: cleanup-only-in-produce siblings of #102 (hasSyncWaiter, numWaiting, sync host-import lenders)

1 participant