Two review blockers, both correct, both about the same failure: a field
or a claim that looks like attribution without being it.
BLOCKER 1 --- owner is not honest before P3. Revision 1 proposed
owner = package-or-builtin while populating it from static
per-subsystem constants at each dispatcher. Those disagree. A generic
dispatcher has no trustworthy knowledge of who invoked it, and
pmacs.process.spawn is callable by any package, so a static "lsp" label
is an origin or category and would confidently misattribute
third-party work to a builtin at exactly the point section 9 wants
attribution.
owner is removed rather than renamed. origin or subsystem would be
honest wording, but a second string field beside purpose, used to group
the view, gets adopted as ownership by the next reader regardless of
its name --- and it would squat on the slot P3 has to fill. Stage 2
needs a grouping key and should get a real one. No P3 alignment is
claimed any more.
BLOCKER 2 --- the handler name needs a mechanism, not a parameter.
Revision 1 said the name was "in hand at the one place that throws it
away". That was wrong about the call chain, and re-reading it is what
showed why: dispatch(name) calls an arbitrary handler, which calls a
Lua wrapper, which calls the Rust binding, and name is a parameter of
none of them. Worse, async.lua:337-345 documents the wrapper layer as
bypassable --- other runtime files are told to call their own raw
_dispatch_* primitives --- so capturing in the wrappers would miss
exactly the callers attribution exists for.
Q#W-2 is rewritten as a contract: a dispatch-name stack owned by the
async runtime and read at allocate, the same single funnel Q#W-1
collapses. Seven rules, including the two that decide whether it is
better than nothing --- unwind-safe popping, because one erroring
handler would otherwise poison every later dispatch with a stale name,
and composition rather than replacement of a caller-supplied purpose,
because replacing recreates blocker 1 in a new place.
It also answers the objection it invites: why is this ambient allowed
when Q#W-5 defers parent for needing one. Because they are different
mechanisms --- this is a synchronous single-threaded extent with a
deterministic pop, and parent needs a lifetime model spanning ticks and
post-settlement callbacks.
Verification takes the reviewer wording fix: presence is a type
obligation now that purpose is non-optional in a private JobSpec, so
the compiler proves it and the tests prove semantics at representative
entry paths. The handler witness must be a registered handler calling a
real dispatcher, not a synthetic funnel test.
The title changed too: "who asked for it" overclaimed once owner left.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai