Skip to content

task core: re-key poisoning refusal onto the poison marker (#173) - #251

Merged
lannbot merged 1 commit into
mainfrom
cm705/poison-rekey
Aug 30, 2026
Merged

task core: re-key poisoning refusal onto the poison marker (#173)#251
lannbot merged 1 commit into
mainfrom
cm705/poison-rekey

Conversation

@lannbot

@lannbot lannbot commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

First implementation PR of the #173 migration (CM#705 adoption), per the revised sequencing in #173 (comment) — pulled ahead of the pin advance because it is behavior-preserving under the current pin.

What

Poisoning (the runtime's named divergence: per-instance corpse semantics instead of store-fatal traps) is currently implemented as "mayEnter stays false forever", with the poisonedInstances WeakMap as a diagnostic shadow (#145). CM#705 deletes may_enter entirely, so this PR flips the dependency: every poisoning decision now reads the marker.

  • New entryRefusal(callee, caller, base) in task/scheduler.ts owns the entry-refusal decision: marker first (with the Go components trap (and poison their instance) when the Go runtime reads the clock inside cabi_realloc #145 cause suffix), then the transient may_enter gate (which CM#705 will delete wholesale), null when enterable. Trap messages are byte-identical to the previous withPoisonCause pattern in all three states; the doc comment carries the equivalence argument.
  • The five trap gates route through it: host entry (exec/boundary.ts), FACT sync/async start-call (intrinsics/fact_calls.ts), enter-sync-call (intrinsics/mod.ts, check-only), dtor entry (cabi/handles.ts).
  • The two non-trap decisions take the marker as an added conjunct: Task.requestCancellation's delivery gate and Store.tick's candidate filter.
  • The entering_set vacuous pass (caller === callee) is preserved by an explicit guard and pinned — the dtor path is the live case.

No bracket-break site, no enterFrom/leaveTo/mayEnterFrom, and no already-marker-keyed site (dispatchableTail, resumeWith's early retire, streams retirement) is touched.

Tests

Six white-box pins (runtime/tests/task_test.ts, "Poisoning re-key") force mayEnter back to true on a marked instance — a state the runtime never produces — to isolate the marker's authority. They must survive the CM#705 pin advance unchanged. All pre-existing pins pass unchanged.

Gates

Full just gates pass locally: core suites, conformance (1257 passed / 0 failed / 112 xfail, no stale xfails), sched-seeds, shells, browser lanes (chromium + firefox OK), smoke-tls, smoke-c0. Not breaking: no published-surface change, conventions goldens untouched.

Poisoning decisions now read the poisonedInstances marker, not the
permanently-false mayEnter it shadows. New entryRefusal helper owns the
entry-refusal decision (marker first with the #145 cause suffix, then the
transient may_enter gate, byte-identical messages); the five trap gates
(host entry, FACT sync/async start-call, enter-sync-call, dtor) route
through it, and the two non-trap decisions (requestCancellation delivery,
tick's candidate filter) take the marker as an added conjunct. The
caller-is-callee vacuous pass of entering_set is preserved and pinned.

Behavior-preserving under the current pin; the point is CM#705 (merged
upstream): when the pin advance deletes may_enter, poisoning survives
untouched because it no longer depends on it. Six white-box pins force
mayEnter back to true on a marked instance to isolate the marker's
authority; they must survive the removal unchanged.
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.

2 participants