You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
But the executor finalizes a cancelled/crashed Run as errored (_finalize_crashed_run → record_run_errored); cancelled is never written. The executor even treats "an errored/cancelled (interrupted)" run as one persisted errored state.
So the documented/typed vocabulary has cancelled, the persisted behavior does not. The resumability outcome is currently correct only by accident (an errored run is resumable, which is what a cancelled run should be), but the status name a user/inspector sees is errored, not cancelled. This drift predates #30; #30 only recorded it honestly in the status.py docstring.
Decision needed (HITL)
Pick one direction, then make issues ↔ docs ↔ code consistent:
(A) Emit a distinct cancelled status. On a deliberate cancellation (an interrupt / cancel surfacing as asyncio.CancelledError), finalize the Run as cancelled rather than errored, so the persisted status matches the glossary and a report can distinguish "cancelled" from "errored by an adapter/internal fault". Keep errored for genuine adapter/internal faults. Requires distinguishing cancellation from other crashes at the finalization seam (ADR 0003's cancel semantics).
(B) Drop cancelled from the vocabulary. Confirm v0.1 does not distinguish cancellation from errored; remove cancelled from CONTEXT.md (Resume Eligibility) and CANCELLED / cancelled from status.pyRunStatus. Interrupted-run resumability is then carried entirely by errored / failed.
Hint: (A) is the more faithful primitive — a user-initiated cancel is not an error — but costs a finalization-seam change; (B) is cheaper and matches current behavior. A human should pick.
Acceptance criteria
A direction (A or B) is chosen and recorded (a short note; if (A), an addendum to ADR 0003).
CONTEXT.md (Resume Eligibility / Error Classification) and src/caw/status.py (RunStatus + the docstring note) agree with the chosen behavior.
If (A): a cancelled Run is persisted with status cancelled (distinct from errored), remains resume-eligible, and is covered by a test through the run-directory / state seam; errored stays for adapter/internal faults.
If (B): no cancelled remains in the vocabulary (CONTEXT.md + status.py), and the status.py docstring note about the gap is removed.
No remaining doc ↔ behavior drift on the cancelled status.
Blocked by
None — can start immediately. It is independent of #117 / #118, but touches the same status vocabulary, so it is best sequenced after #118 lands to avoid churn.
Problem
cancelledexists in the run-status vocabulary but the v0.1 kernel never produces it:CONTEXT.md(Resume Eligibility) listscancelledamong the resumable interrupted runs (failed, errored, cancelled).src/caw/status.py(the Own run/node status, event types, and attempt numbers in one place #30 status owner) carriesCANCELLEDinRunStatus.errored(_finalize_crashed_run→record_run_errored);cancelledis never written. The executor even treats "an errored/cancelled (interrupted)" run as one persistederroredstate.So the documented/typed vocabulary has
cancelled, the persisted behavior does not. The resumability outcome is currently correct only by accident (anerroredrun is resumable, which is what a cancelled run should be), but the status name a user/inspector sees iserrored, notcancelled. This drift predates #30; #30 only recorded it honestly in thestatus.pydocstring.Decision needed (HITL)
Pick one direction, then make issues ↔ docs ↔ code consistent:
cancelledstatus. On a deliberate cancellation (an interrupt / cancel surfacing asasyncio.CancelledError), finalize the Run ascancelledrather thanerrored, so the persisted status matches the glossary and a report can distinguish "cancelled" from "errored by an adapter/internal fault". Keeperroredfor genuine adapter/internal faults. Requires distinguishing cancellation from other crashes at the finalization seam (ADR 0003's cancel semantics).cancelledfrom the vocabulary. Confirm v0.1 does not distinguish cancellation fromerrored; removecancelledfromCONTEXT.md(Resume Eligibility) andCANCELLED/cancelledfromstatus.pyRunStatus. Interrupted-run resumability is then carried entirely byerrored/failed.Hint: (A) is the more faithful primitive — a user-initiated cancel is not an error — but costs a finalization-seam change; (B) is cheaper and matches current behavior. A human should pick.
Acceptance criteria
CONTEXT.md(Resume Eligibility / Error Classification) andsrc/caw/status.py(RunStatus+ the docstring note) agree with the chosen behavior.cancelled(distinct fromerrored), remains resume-eligible, and is covered by a test through the run-directory / state seam;erroredstays for adapter/internal faults.cancelledremains in the vocabulary (CONTEXT.md+status.py), and thestatus.pydocstring note about the gap is removed.cancelledstatus.Blocked by
None — can start immediately. It is independent of #117 / #118, but touches the same status vocabulary, so it is best sequenced after #118 lands to avoid churn.
Related: #30 (status owner, PR #118),
src/caw/executor.pyfinalization path, ADR 0003.