One concept has one home. Externally initiated lifecycle operations (cancel, pause, resume, answer) are methods on the existing handles (Run in deck.py, Runtime.signal in runtime/service.py); state transitions flow through the runtime's state machine.
Good (real, deck.py): timeout-like behavior asks the existing handle:
await run.cancel(reason="timeout")Bad, the classic agent artifact:
class TimeoutManager: # second lifecycle path
def _terminate_run(self): ...A close or abandon path that writes nothing says so, and separates the anomalous half from the benign one. The caller has already logged that it closed the run, so a bare return leaves the operator record and the log disagreeing with nothing in between to explain which is right.
Good (real, runtime/service.py):
if started is None:
logger.error(
"run %s is being abandoned but has no run.started to close it against; it stays "
"open in the log until something reconciles it (#419)",
run_id,
)
return
if (status := await self._store.run_status(ctx)) is not RunStatus.RUNNING:
logger.debug("run %s is %s, not RUNNING; it closed itself and nothing was written", run_id, status)
returnBad:
if started is None or await self._store.run_status(ctx) is not RunStatus.RUNNING:
returnRules:
- No
*Manager/*Controller/*Handlerclass whose responsibility an existing handle owns; checkuv run scripts/repomap.pyfirst. - An early return on a
close_*/_close_*/_abandon*path names the run and why it wrote nothing: a run already over isdebug, an unreadable opening iserror. - Never mutate run state directly; go through the transition path.
asyncio.create_taskbelongs to the runtime (runtime/dispatch.py,runtime/service.py,deck.py); a task created elsewhere bypasses the run's cancellation and drain guarantees (enforced by ruff TID251). One exception, allowlisted with its own owner: the native executor runs a@workflowbody that parks mid-await, so the coroutine outlives the call that started it - it is held in that executor's own registry and cancelled by itsaclose().- Control verbs are signals, not errors: honoring a cancel raises
ControlSignalled, which records the effect.