tasks: 59 also clears the workspaces a phase leaves behind

complete_task works from the stem of the card it is completing, so a
finished phase leaves every member's worktree, local branch and remote
branch in place — measured on 53: three worktrees at 3.8M each and two
member branches still on origin. The sweep now removes them, with the
existing rule intact for a member that never merged: there is work in
that worktree, so it stays.
This commit is contained in:
istos
2026-08-02 07:33:55 +02:00
parent 93f0304a2c
commit d978d6ad42
@@ -1,14 +1,17 @@
# 59 — Finishing a phase finishes its cards
# 59 — Finishing a phase finishes its cards, and clears up after them
**Status:** Backlog
**Priority:** Medium — without it a phase ends by handing you a pile of
cards you have already judged
cards you have already judged and a heap of checkouts nobody will
remember to delete
**Type:** Feature
When a phase's PR merges into `main`, its members' work is in `main` too —
but their cards are sitting in `review/`, where the board says they are
waiting on you. **Merge & clean up** on a phase card should move its
members to `done/` in the same operation that moves the phase.
waiting on you, and every one of them has left a worktree and three
branches behind. **Merge & clean up** on a phase card should finish its
members too: move them to `done/`, and clear the workspaces they are done
with.
## Context
@@ -29,6 +32,16 @@ members to `done/` in the same operation that moves the phase.
- Board-made moves commit themselves under `BOARD_COMMIT_MOVES` and, in
team mode, push — so a sweep of five cards is five commits or one, and
which it is deserves a decision rather than an accident.
- **The cleanup half is missing entirely.** `complete_task` works from
`stem = filename[:-3]`, so it removes the worktree and branch of the
card being completed and knows nothing about members. Measured on phase
53 after it finished: three worktrees still on disk
(`.worktrees/47-…`, `.worktrees/52-…`, `.worktrees/53-…`, 3.8M each),
both member branches still local, and both still on origin. A grep of
`phases.py` finds worktrees created and never removed.
- An ordinary card already gets the full treatment on completion —
worktree removed, local branch deleted, remote branch deleted after the
push. Members should get exactly that, from the same place.
**Affected areas:** `manager/core/github.py` (`complete_task`), and
whatever narrates the result.
@@ -38,9 +51,17 @@ whatever narrates the result.
- **The sweep, inside the merge.** When a phase card is completed, every
member the phase lists moves to `done/` as part of the same operation —
after the merge into `main` has actually succeeded, never before.
- **Clear each merged member's workspace**, the way completing an
ordinary card clears its own: remove the worktree, delete the local
branch, delete the branch on the remote. The member's work is in `main`
by then, so there is nothing in any of them worth keeping.
- **Only what the phase merged.** A member that never reached the phase
branch — halted, held, walked back — is not swept. It stays where it
is, and it is the reason a person will look at the phase afterwards.
branch — halted, held, walked back — is neither moved nor cleared. Its
card stays where it is, and so do its worktree and its branch: there is
work in them, and it is the reason a person will look at the phase
afterwards. The board already applies this rule to a failed run that
committed something, and removing a worktree with work in it is the one
unrecoverable thing in this card.
- **Narrate it as one thing.** The ticker should say a phase finished and
how many cards went with it, not five separate moves scrolling past. A
person watching should see one event, because one thing happened.
@@ -73,8 +94,13 @@ whatever narrates the result.
number of cards.
- [ ] Given the merge fails or conflicts, nothing moves — not the phase
card, not one member.
- [ ] Given a member that never reached the phase branch, it is left
exactly where it is.
- [ ] Given a member that never reached the phase branch, its card, its
worktree and its branch are all left exactly as they are.
- [ ] Given the phase completes, no merged member leaves a worktree,
a local branch or a branch on the remote behind — `git worktree
list` and `git branch` name only what was there before the phase.
- [ ] Removing a worktree never discards uncommitted changes: a member
with a dirty worktree is reported and kept, not forced.
- [ ] Given "just move the card" instead, no member moves.
- [ ] Given the phase card is archived rather than merged, its members
reappear on the board in their own stages and none of them is
@@ -97,3 +123,10 @@ The reason it is separate from card 56 rather than folded in: 56 is about
what the *Board view draws*, and this is about what the *board does*. One
is a rendering rule, the other moves files and commits them. Keeping them
apart also keeps 56 shippable on its own.
**Why the cleanup is not cosmetic.** A stale worktree is not just disk —
`start_agent` refuses to launch a card whose worktree already exists on
the wrong branch, so a leftover from a finished phase is a trap laid for
whoever reopens that card. And the accumulation is per member per phase:
five-card phases leave five checkouts and fifteen branches each time,
until somebody notices and does it by hand.