Spec. A4 already lists abandon as a way out of a halt ("continue, re-plan, or abandon, on the operator's word"), and 0.2 closes a work item as "completed or abandoned", but there was no command for it. This edits the spec in place:
B1: gains the edge "any waiting state → [abandon] → IDLE".
B2: gains the command and its effects.
Behaviour (control.py)
abandon works from either sign-off gate, AWAIT_INPUT or PR_OPEN, and ends in IDLE with the task cleared. The transition table gains the two gate → IDLE edges.
The move to IDLE is saved first; the Gitea tidy-up comes after. The tidy-up closes the plan issue and any open milestone PR, each with an "abandoned by " note, and keeps the branches. A Gitea failure is reported ("could not close …") and never leaves a live task behind a closed issue. An earlier draft had this backwards; the transition failure the tests caught showed why the order matters.
Any unresolved intent is marked aborted, so boot reconciliation doesn't gate on work dropped on purpose.
Like status, it's a command in every state: in AWAIT_INPUT it isn't taken as the answer to a question. While work runs, stop comes first (the existing "busy; say 'stop'" reply). In IDLE the reply is "nothing to abandon".
The prompts that offer choices mention it: the restart / stranded question and the PR_OPEN hint.
Gitea:GiteaClient.close_issue, PlanBoard.close and MilestonePublisher.close_pull_request (each comments, then closes).
Tests:test_abandon.py covers abandon from each waiting state (then use starts cleanly), from a question, closing the PR, aborting a pending intent, Gitea being down, and no active task. test_gitea.py checks the close calls against the real client. 465 unit tests and the integration suite (19 passed, 7 skipped) pass; lint and format clean.
This completes the three-PR state-machine review (#66, #68, this).
PR 3 of the state-machine review.
**Spec.** A4 already lists abandon as a way out of a halt ("continue, re-plan, or abandon, on the operator's word"), and 0.2 closes a work item as "completed or abandoned", but there was no command for it. This edits the spec in place:
- **B1:** gains the edge "any waiting state → [abandon] → IDLE".
- **B2:** gains the command and its effects.
**Behaviour** (`control.py`)
- **`abandon`** works from either sign-off gate, `AWAIT_INPUT` or `PR_OPEN`, and ends in `IDLE` with the task cleared. The transition table gains the two gate → `IDLE` edges.
- **The move to `IDLE` is saved first; the Gitea tidy-up comes after.** The tidy-up closes the plan issue and any open milestone PR, each with an "abandoned by <operator>" note, and keeps the branches. A Gitea failure is reported ("could not close …") and never leaves a live task behind a closed issue. An earlier draft had this backwards; the transition failure the tests caught showed why the order matters.
- **Any unresolved intent is marked aborted**, so boot reconciliation doesn't gate on work dropped on purpose.
- **Like `status`, it's a command in every state:** in `AWAIT_INPUT` it isn't taken as the answer to a question. While work runs, `stop` comes first (the existing "busy; say 'stop'" reply). In `IDLE` the reply is "nothing to abandon".
- **The prompts that offer choices mention it:** the restart / stranded question and the `PR_OPEN` hint.
- **Gitea:** `GiteaClient.close_issue`, `PlanBoard.close` and `MilestonePublisher.close_pull_request` (each comments, then closes).
**Tests:** `test_abandon.py` covers abandon from each waiting state (then `use` starts cleanly), from a question, closing the PR, aborting a pending intent, Gitea being down, and no active task. `test_gitea.py` checks the close calls against the real client. 465 unit tests and the integration suite (19 passed, 7 skipped) pass; lint and format clean.
This completes the three-PR state-machine review (#66, #68, this).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
A4 already names abandon as one of the ways out of a halt (continue,
re-plan, or abandon) and 0.2 closes a work item as completed or
abandoned, but no command did it: from a gate or a question the only way
to drop a task was to edit the state database.
- 'abandon' ends the task from any waiting state and returns to IDLE.
The move is made durable first; then the plan issue and any open
milestone PR are closed with a note (branches kept), and any
unresolved intent is aborted so boot reconciliation does not gate on
work dropped on purpose. A Gitea failure is reported, not fatal.
- Like 'status' it is a command in every state, never read as an answer
or feedback. While work runs, 'stop' comes first, as before.
- The restart / stranded question and the PR_OPEN hints mention it.
- Spec: B1 gains the abandon edge and B2 the command.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
PR 3 of the state-machine review.
Spec. A4 already lists abandon as a way out of a halt ("continue, re-plan, or abandon, on the operator's word"), and 0.2 closes a work item as "completed or abandoned", but there was no command for it. This edits the spec in place:
Behaviour (
control.py)abandonworks from either sign-off gate,AWAIT_INPUTorPR_OPEN, and ends inIDLEwith the task cleared. The transition table gains the two gate →IDLEedges.IDLEis saved first; the Gitea tidy-up comes after. The tidy-up closes the plan issue and any open milestone PR, each with an "abandoned by " note, and keeps the branches. A Gitea failure is reported ("could not close …") and never leaves a live task behind a closed issue. An earlier draft had this backwards; the transition failure the tests caught showed why the order matters.status, it's a command in every state: inAWAIT_INPUTit isn't taken as the answer to a question. While work runs,stopcomes first (the existing "busy; say 'stop'" reply). InIDLEthe reply is "nothing to abandon".PR_OPENhint.GiteaClient.close_issue,PlanBoard.closeandMilestonePublisher.close_pull_request(each comments, then closes).Tests:
test_abandon.pycovers abandon from each waiting state (thenusestarts cleanly), from a question, closing the PR, aborting a pending intent, Gitea being down, and no active task.test_gitea.pychecks the close calls against the real client. 465 unit tests and the integration suite (19 passed, 7 skipped) pass; lint and format clean.This completes the three-PR state-machine review (#66, #68, this).
🤖 Generated with Claude Code
https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE