- session.killJob maps job-not-found from the lookup only: jobs.get gates the
same synchronous span, so a producer-cancel throw now propagates per the
registry contract (job state unchanged) instead of masquerading as a lookup
failure (threads r3860226021, r3860226047).
- session.killJob applies the service-wide subagent ownership fence exactly as
cancel does; a subagent-owned live session rejects with the ownership error
and the child-owned job stays running (thread r3860226041).
- The stop control stays pending on an admitted kill: the unary response and
the jobs frames have no cross-carrier ordering, so only the authoritative
frame (the row leaving the killable set) releases the button, closing the
duplicate-kill window (thread r3860226028).
- One-line comment on the killReason assignment stating last-writer-wins is
intended, beside the first-claim-wins reported handling (thread r3860225999).
Host spec pins the producer-throw propagation and the fence; the component
spec pins pending-until-frame; the Agent Note records both refinements.
The web task list gains a two-press stop control on running job rows, built on
one seam change: JobRegistry.kill now takes { reason?, reported? } instead of a
positional reason. reported defaults to true (the model's job_kill claims the
terminal report exactly as before); the web path passes reported: false because
a human kill has no model-visible channel, so the settlement flows through the
existing tool-jobs completion notice (wakeup/inject, budgets, truncation all
unchanged). A recorded kill reason merges into a killed settlement's detail
(producer facts first: 'signal: SIGTERM; cancelled by the user'), so the notice
and the web row both say who stopped the work.
- session-controller: session.killJob Remote beside cancel, live-only Agent
lookup, job-not-found/jobs-unavailable rejections joined to the closed RPC
error table; ClientSession.killJob and the ISession face carry it to the UI.
- ui-activity: arm/confirm stop button (3s disarm, pending disable, failure
hint), rendered only on running job rows; standalone activities keep no kill
handle and the README limitation now says so.
- The background-job-list web e2e now drives the whole human path through the
button; goldens show the merged killed detail end to end.
- Agent Note 2026-08-26-human-job-kill records the decision against Kimi's
suppress-own-notification precedent and Claude Code's silent-kill failure;
the 2026-08-08 blocker note and the unified-task-list note point at it.
The goal domain has been served by GoalService's @Remote namespace since it
shipped; the API Proxy copy was a second implementation of the same six
mutations. Remove the goals contract, schemas, route rows, IApiClient stub,
host implementation, and the fixture's compatibility face, leaving
ctx.remote.goals as the only path.
The fixture's goal fold keeps its coverage through the Goal Remotes: its
lifecycle case moves out of the unary-dispatch test, which no longer has
goal rows to cover.
Render reconstructable system prompts at each request-series boundary, preserve series declarations through pre-step wrappers, and keep the presentation and replay snapshots aligned across clients.