Parent
Part of #204 (Phase 4: Hardening)
Problem
Every polecat creates a branch on the remote when it pushes work, and every convoy creates a feature branch. After the refinery merges the code (direct or PR), these branches are never cleaned up. Over time, rigs accumulate dozens to hundreds of stale branches:
- Polecat work branches:
convoy/<slug>/<id>/<agent>/<bead> or gt-polecat/<agent>/<bead>
- Convoy feature branches:
convoy/<slug>/<id>/head
- Failed/abandoned branches from agents that crashed mid-work
There is zero branch cleanup code anywhere in the codebase — no git push --delete, no remote prune, nothing.
Solution: Refinery cleans up after itself
The refinery is the natural owner of branch cleanup — it's the last thing that touches a branch before it's no longer needed. After a successful merge (direct or PR), the refinery should delete the source branch from the remote.
When to delete
| Scenario |
Branch to delete |
When |
| Direct merge to main |
Polecat's work branch |
After successful git push of the merge |
| PR created |
Polecat's work branch |
After PR is merged (detected by pollPendingPRs) — most Git platforms auto-delete on merge, but this should be explicitly handled |
| Convoy intermediate merge |
Polecat's work branch (merged into feature branch) |
After successful merge into the feature branch |
| Convoy landed |
Convoy feature branch (convoy/<slug>/<id>/head) |
After the landing merge to main succeeds |
How to delete
git push origin --delete <branch-name>
This is a single git command executed by the refinery agent (or the container's git manager) after a successful merge. It needs the same credentials used for the merge push.
Implementation options
Option A — Refinery agent does it (prompt-driven): Add to the refinery system prompt: "After a successful merge, delete the source branch from the remote with git push origin --delete <branch>." The refinery already has git access and push credentials. Simplest approach but relies on LLM compliance.
Option B — Container git manager does it (deterministic): Add a deleteBranch(rigId, branchName) function to the container's git manager. The TownDO calls it after completeReviewWithResult reports a successful merge. More reliable than prompt-driven.
Option C — Alarm-based sweep (catch-all): A periodic alarm sub-task queries for closed/merged MR beads, collects their branch names from review_metadata.branch, and batch-deletes any that still exist on the remote. Handles edge cases where options A/B missed a branch (agent crash, container restart, etc.).
Recommended: Option B as primary + Option C as safety net. The refinery's merge completion path (completeReviewWithResult with status: 'merged') deterministically triggers branch deletion. The alarm sweep catches anything that slipped through.
Convoy feature branch lifecycle
Convoy feature branches need special handling:
- Do NOT delete during intermediate merges — polecat branches are deleted, but the feature branch stays alive for subsequent beads
- Delete after landing merge — once the feature branch is merged to main (in
processConvoyLandings), delete it
- Delete on convoy close/fail — if a convoy is force-closed or failed, clean up its feature branch
Edge cases
- Failed merges: Don't delete the branch — it may be needed for retry or rework
- Open PRs: Don't delete the branch until the PR is merged or closed
- Abandoned branches: Branches from failed/crashed agents that never made it to review. The alarm sweep should catch these by checking for branches with no corresponding open/in_progress MR bead older than a configurable threshold (e.g., 7 days).
- Branch delete fails: Non-fatal — log a warning, the alarm sweep will retry. Don't fail the merge because cleanup failed.
- Protected branches: Never attempt to delete the default branch or any branch matching a configurable protection pattern.
Acceptance Criteria
Notes
- No data migration needed
- Branch names are already stored in
review_metadata.branch and convoy feature branches in convoy_metadata.feature_branch — no new data collection needed
- Most GitHub/GitLab platforms have a "delete branch on PR merge" option that users can enable at the repo level. The alarm sweep should account for branches that were already deleted by the platform.
git push origin --delete will fail silently (exit code 1) if the branch doesn't exist — handle gracefully
Parent
Part of #204 (Phase 4: Hardening)
Problem
Every polecat creates a branch on the remote when it pushes work, and every convoy creates a feature branch. After the refinery merges the code (direct or PR), these branches are never cleaned up. Over time, rigs accumulate dozens to hundreds of stale branches:
convoy/<slug>/<id>/<agent>/<bead>orgt-polecat/<agent>/<bead>convoy/<slug>/<id>/headThere is zero branch cleanup code anywhere in the codebase — no
git push --delete, no remote prune, nothing.Solution: Refinery cleans up after itself
The refinery is the natural owner of branch cleanup — it's the last thing that touches a branch before it's no longer needed. After a successful merge (direct or PR), the refinery should delete the source branch from the remote.
When to delete
git pushof the mergepollPendingPRs) — most Git platforms auto-delete on merge, but this should be explicitly handledconvoy/<slug>/<id>/head)How to delete
This is a single git command executed by the refinery agent (or the container's git manager) after a successful merge. It needs the same credentials used for the merge push.
Implementation options
Option A — Refinery agent does it (prompt-driven): Add to the refinery system prompt: "After a successful merge, delete the source branch from the remote with
git push origin --delete <branch>." The refinery already has git access and push credentials. Simplest approach but relies on LLM compliance.Option B — Container git manager does it (deterministic): Add a
deleteBranch(rigId, branchName)function to the container's git manager. The TownDO calls it aftercompleteReviewWithResultreports a successful merge. More reliable than prompt-driven.Option C — Alarm-based sweep (catch-all): A periodic alarm sub-task queries for closed/merged MR beads, collects their branch names from
review_metadata.branch, and batch-deletes any that still exist on the remote. Handles edge cases where options A/B missed a branch (agent crash, container restart, etc.).Recommended: Option B as primary + Option C as safety net. The refinery's merge completion path (
completeReviewWithResultwithstatus: 'merged') deterministically triggers branch deletion. The alarm sweep catches anything that slipped through.Convoy feature branch lifecycle
Convoy feature branches need special handling:
processConvoyLandings), delete itEdge cases
Acceptance Criteria
Notes
review_metadata.branchand convoy feature branches inconvoy_metadata.feature_branch— no new data collection neededgit push origin --deletewill fail silently (exit code 1) if the branch doesn't exist — handle gracefully