Today the task saga only knows one compensation: CompensationKind.REMOVE_WORKTREE. When a worker dies mid-flight, recovery.py reaps its worktree but the loop/ git branch it created is left orphaned. branch_sweep.sweep only deletes a loop branch once issue #n is CLOSED (the landed-signal) — but a FAILED saga's issue is still OPEN, so the branch is invisible to GC and accumulates until a human deletes it. The saga that created the branch must own the arc that reclaims it. This epic adds a DELETE_BRANCH compensation kind, enqueues it at dispatch, drives it through recovery for stale/failed sagas, and preserves the never-half-compensated integrity guarantee when branch deletion fails. Sub-tickets are each one shippable PR.
Customer story
As an operator dispatching workers on a real repository without trusting worker-created state: a crashed worker leaves an orphan loop/ branch that branch GC never reaps (it only fires on issue-close, and the issue is still open), so my branch list grows with every failed task. The saga that planted the branch should reclaim it as a compensation.
Today the task saga only knows one compensation: CompensationKind.REMOVE_WORKTREE. When a worker dies mid-flight, recovery.py reaps its worktree but the loop/ git branch it created is left orphaned. branch_sweep.sweep only deletes a loop branch once issue #n is CLOSED (the landed-signal) — but a FAILED saga's issue is still OPEN, so the branch is invisible to GC and accumulates until a human deletes it. The saga that created the branch must own the arc that reclaims it. This epic adds a DELETE_BRANCH compensation kind, enqueues it at dispatch, drives it through recovery for stale/failed sagas, and preserves the never-half-compensated integrity guarantee when branch deletion fails. Sub-tickets are each one shippable PR.
Customer story
As an operator dispatching workers on a real repository without trusting worker-created state: a crashed worker leaves an orphan loop/ branch that branch GC never reaps (it only fires on issue-close, and the issue is still open), so my branch list grows with every failed task. The saga that planted the branch should reclaim it as a compensation.