bug(prune): --delete-branches --remote deletes branches never shown by any preview, and reports counts instead of names #301

Closed
opened 2026-07-20 15:32:44 +00:00 by hexajon · 0 comments
hexajon commented 2026-07-20 15:32:44 +00:00 (Migrated from codeberg.org)

Live occurrence, 2026-07-20 (transcript below genericized; counts exact).

What happened

$ madtea prune
Would prune 1 stale remote-tracking ref(s)
Found 34 merged branch(es):
  [... 34 branch names ...]
Re-run with delete_branches=true (CLI: --delete-branches) to delete; add --remote
to also find merged remote-only branches not shown above (widens the deletion set).

$ madtea prune --delete-branches --remote
Pruned 1 stale remote-tracking ref(s)
Deleted 34 local branch(es)
Deleted 36 remote branch(es)
Cleaned 36 stale remote-tracking ref(s)

The problems

  1. Two remote branches were deleted that no output ever named. The dry run listed 34; the delete removed 36 remote branches. The dry-run hint even acknowledges the widening ("widens the deletion set") - but its own suggested re-run puts --delete-branches and --remote together, so the natural next command deletes a set that was never previewed. The safe flow it presumably intends (run prune --remote as a dry run first, read the widened list, then add --delete-branches) is neither stated nor enforced.

  2. The deletion output is counts-only. "Deleted 36 remote branch(es)" leaves no record of which branches died, so the two never-previewed deletions cannot even be identified after the fact. Every other destruction surface in madtea names what it acts on; prune's execute path should too - at minimum for anything not shown by the preceding preview.

  3. This is the same class as #63 (dry-run lists fewer than --remote deletes), addressed by PR #100's set-parity work - the combined --delete-branches --remote invocation is evidently still outside that parity guarantee.

The deletions themselves were content-verified merged branches (no work lost - that guarantee held). This is a visibility/consent-shape bug, not a data-loss bug.

Acceptance

  • Invariant: every branch a prune run deletes was either named by a preview in that same invocation (execute path prints the widened list before acting) or is named in the deletion output - no count-only reporting of never-listed deletions
  • The dry-run hint's suggested re-run does not steer users into deleting an unpreviewed set (either the execute path self-previews, or the hint explicitly says to dry-run --remote first)
  • A test pins set parity for the combined --delete-branches --remote path specifically (the #100 parity coverage extended to this invocation shape)
  • Deletion output names deleted branches (grouped local/remote), with counts as the summary line, not the whole record
Live occurrence, 2026-07-20 (transcript below genericized; counts exact). ## What happened ``` $ madtea prune Would prune 1 stale remote-tracking ref(s) Found 34 merged branch(es): [... 34 branch names ...] Re-run with delete_branches=true (CLI: --delete-branches) to delete; add --remote to also find merged remote-only branches not shown above (widens the deletion set). $ madtea prune --delete-branches --remote Pruned 1 stale remote-tracking ref(s) Deleted 34 local branch(es) Deleted 36 remote branch(es) Cleaned 36 stale remote-tracking ref(s) ``` ## The problems 1. **Two remote branches were deleted that no output ever named.** The dry run listed 34; the delete removed 36 remote branches. The dry-run hint even acknowledges the widening ("widens the deletion set") - but its own suggested re-run puts `--delete-branches` and `--remote` together, so the natural next command deletes a set that was never previewed. The safe flow it presumably intends (run `prune --remote` as a dry run first, read the widened list, then add `--delete-branches`) is neither stated nor enforced. 2. **The deletion output is counts-only.** "Deleted 36 remote branch(es)" leaves no record of *which* branches died, so the two never-previewed deletions cannot even be identified after the fact. Every other destruction surface in madtea names what it acts on; prune's execute path should too - at minimum for anything not shown by the preceding preview. 3. This is the same class as #63 (dry-run lists fewer than `--remote` deletes), addressed by PR #100's set-parity work - the combined `--delete-branches --remote` invocation is evidently still outside that parity guarantee. The deletions themselves were content-verified merged branches (no work lost - that guarantee held). This is a visibility/consent-shape bug, not a data-loss bug. ## Acceptance - [ ] Invariant: every branch a prune run deletes was either named by a preview in that same invocation (execute path prints the widened list before acting) or is named in the deletion output - no count-only reporting of never-listed deletions - [ ] The dry-run hint's suggested re-run does not steer users into deleting an unpreviewed set (either the execute path self-previews, or the hint explicitly says to dry-run `--remote` first) - [ ] A test pins set parity for the combined `--delete-branches --remote` path specifically (the #100 parity coverage extended to this invocation shape) - [ ] Deletion output names deleted branches (grouped local/remote), with counts as the summary line, not the whole record
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#301
No description provided.