branches-remote delete drops an unmerged remote ref with no containment proof #568
Labels
No labels
breaking
bug
documentation
enhancement
epic
good first issue
help wanted
refactoring
resolution/duplicate
resolution/invalid
resolution/wontfix
security
severity/critical
severity/high
severity/low
severity/medium
status/abandoned
status/blocked
status/needs-decision
status/needs-info
status/needs-verification
testing
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
#563 Epic: the destructive surface has outgrown ADR 0029's classification table
sixfold-space/madtea
Reference
sixfold-space/madtea#568
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #563.
The defect
madt_branches_remote action=deletedeletes one or more branches on the forge with no containment check. Its own summary says so: "Delete branch(es) on the REMOTE (local branches untouched; no merged check)" (internal/mcp/tools_branches.go:68-70). The implementation isbranchesDelete(internal/mcp/tools_branches_crud.go:40-49). The CLI twin isinternal/cmd/branchapi/branchapi.go:90.It is ungated, it accepts a batch, and it computes no proof of any kind. A remote branch holding commits that exist in no other ref is deleted on request.
ADR 0029's per-operation table carries one branch-delete row, which reads:
| branch delete | CLI
branch -d+ MCPmadt_branch_delete| machine-proof |git branch -donly, git refuses an unmerged branch |A reader takes that as a statement about branch deletion in madtea. It is a statement about one of the two branch deletes madtea ships. The table never names the other one, so the record reads as covering a surface it does not cover.
madt_prune's help routes callers here for branches prune will not take (internal/mcp/help_generated.go:3340), which means the unproven path is the documented next step after the proven one refuses.What needs deciding
The classification is genuinely open, so this should not be closed by picking one silently.
findRemoteOrphansalready uses in prune (internal/service/prune/run.go:407-413). That keeps the operation and earns the carve-out.My lean is option 2, because the check already exists in the codebase and the operation is genuinely useful.
Acceptance criteria
madt_prune's help no longer routes a refused branch to an unproven delete, unless that delete has earned the carve-out by then.