`▸ run phase` guarded its own door and left the neighbour's open:
`/api/agent/start` accepted a phase card, cut `task/<stem>` and handed a
list of other cards to a work agent as a brief. It did that once, and the
agent implemented two cards at once in a worktree nobody was watching.
The refusal is a server rule, in `_validate` with the stage check — ahead
of the claim and well ahead of the worktree, so it costs nothing and
leaves nothing to clean up — and it names ▸ run phase rather than just
saying no. Which headless kinds a phase card may host is now decided kind
by kind where the guard lives: ▸ start work and ↻ act on PR refuse it
(both are work agents), while ◔ still true? and ◔ review PR are allowed —
the latter now told the phase's own branch, since its PR is from
`phase/<stem>` and `task/<stem>` was never cut. The guard is about
starting, so a card retyped under a running agent is left alone.
And the card says which state it is in: an `in-progress/` phase nobody has
started read exactly like one mid-run, the header chip being absent in
both cases. It now wears `not started` (or `held`) in the settled
register, with the line under it saying what ▸ run phase would do — never
the accent, the breathing mark or the caret, which mean work is happening.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A work agent ended its turn to wait for a four-minute test suite it had backgrounded, and the run ended with it: 314 lines of passing work staged and never committed, an empty branch, a halted phase. Nothing in the prompts said the run was a single non-interactive turn, so waiting looked like a sensible strategy.
All four core prompts now open with the same block: this is one turn, the process exits with your reply, and nothing you meant to finish afterwards survives. It names the trap directly — do not background a command and end the turn to wait for it, do not promise to come back — and each template follows it with what its own run loses: work.md commits around long-running commands, act-pr.md commits and pushes, review-pr.md posts its verdict inside the turn, review.md writes its report there.
The block sits before the task body and carries no braces, so str.format still renders it and the NOT READY / ADDRESSED / PR REVIEW / RELEVANCE REVIEW marker lines keep their place after it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Runs 55 (the prompt says the run is one turn), then 54 (start_agent
refuses a phase card), then 46 (a board with no runnable commands says
so). No card depends on another; 55 is prompt-only and goes first, 54
and 46 both edit board.html so they run adjacent.
Also the first exercise of the Phases view: 56-59 landed after phase 53
finished, so hiding, the lane, the move refusal and the sweep have not
yet been watched on a live run.
Merge & clean up on a phase card now ends the phase: after the merge into
main has actually succeeded, every member the phase merged moves to done/
and its workspace is cleared the way completing an ordinary card clears
its own — worktree removed, local branch deleted, branch on the remote
deleted.
Only what the phase merged. A member is swept when its card settled into
review/ or done/ and its branch is contained in the phase branch (or
there was never a branch to bring) — the same pair the runner reads a
member as merged by. One that halted, was held or was walked back keeps
its card, its worktree and its branch: there is work in them.
Nothing uncommitted is thrown away: a member's worktree comes out without
--force, and a dirty one is reported in the ticker and kept with its
branch rather than forced.
One ending, told once. taskfiles.move_together moves the cards in a
single commit naming all of them (`board: 47, 52 → done with phase 53`,
so it publishes in team mode like any other board commit), and the moves
are marked quiet so the watcher does not also scroll five identical move
lines behind the one line the ending gets.
The other endings are untouched: "just move the card" and archiving the
phase card move no member, because neither puts anything in main.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>