Skip to content

Reconcile the cancelled run status: the kernel persists cancellation as errored, never cancelled #119

Description

@qinhaihong-red

Problem

cancelled exists in the run-status vocabulary but the v0.1 kernel never produces it:

  • CONTEXT.md (Resume Eligibility) lists cancelled among 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) carries CANCELLED in RunStatus.
  • 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.py RunStatus. 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.

Related: #30 (status owner, PR #118), src/caw/executor.py finalization path, ADR 0003.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions