feat(skills): add branch-supersede-check - #183
Conversation
`git diff main...branch` is the wrong instrument for "does this branch still matter", and it fails silently. The three-dot form compares against the merge base, so it lists everything the branch did since it forked — whether or not trunk has since acquired the same content by a squash merge, a cherry-pick, or someone doing the work again in another PR. A branch whose work landed months ago renders exactly like one holding something unique. Four branches in one day looked unmerged and were not. What settled each of them was a per-file comparison against trunk as it is now, which is what this script automates: every touched file is labelled IDENTICAL, BASE-AHEAD, BRANCH-AHEAD, DIVERGED or ONLY-ON-BRANCH. Building it changed what it says. The first version gave a binary verdict, and against all four real branches it answered "has unique content" — technically true every time, and misleading every time. So it now looks up a merged PR for the branch head (squash merging leaves neither ancestry nor identical files), grades the verdict rather than ruling, and ends with the limit stated outright: this tool compares text, not worth. A DIVERGED file usually means the branch is behind, not ahead. Read-only. Never checks out, merges, or deletes; the single network call is the PR lookup, skippable with --no-pr. Symlinked into .claude/skills so it is discoverable, and ~/.agents/skills points at this copy too — one source of truth for both agent tools. Verified: shellcheck clean, check-skills OK, mq-skills audit reports 8 skills 8 indexed 8 discoverable, full selftest suite green, and the script reproduces the two real classifications it was built from (a squash-merged branch as superseded, and a 7-of-11-identical branch as leaning superseded). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A branch sharing no history with trunk was reported as superseded. Without a merge base the three-dot diff fails, the failure was discarded, and the empty file list was counted as zero unique files — which reads exactly like a branch whose work already landed. The tool exists to prevent wrong deletions and was recommending one. Both halves are now guarded: a missing merge base is a lookup error, and the diff is taken once with its status checked rather than run twice into /dev/null. The merged-PR lookup asked GitHub for 200 recent PRs and filtered locally, so an older branch — the usual subject of this question — could fall off the end. It now filters server-side by head branch, and a failed lookup says so instead of passing for "no merged PR exists". Adds tests/branch-supersede-smoke.sh; the script had no test at all.
The script had no row in tests/manifest.tsv and no line in test-all.sh, so the new test would have sat there unrun — the exact failure that manifest exists to catch. SKILL.md documented the old 200-PR lookup and described exit 2 as bad usage only.
P1 fixed — and it was worse than the reportReproduced first. An orphan branch holding a file So the tool recommended deleting a branch that shares not one commit with trunk Two guards, both added:
They are redundant by design: either alone closes the hole. The test proves the P2 fixed
One thing the report did not raise, found while testing it: a failed lookup Test
Verified failable against three planted defects (guards removed, Full suite: 85 active tests, shell lint at warning severity over 216 files,
|
git diff main...branchis the wrong instrument for the question "does this branch still matter", and it fails silently.The three-dot form compares against the merge base — the point where the branch forked. It lists everything the branch did since then, whether or not trunk has since acquired the same content by another route: a squash merge, a cherry-pick, someone doing the work again in a different PR. A branch whose work landed months ago produces exactly the same shape of output as one holding something unique. Same file count, same additions, same confident
+325 insertions.Four branches in one day looked unmerged and were not. What settled each was a per-file comparison against trunk as it is now.
What the script does
Labels every file the branch touched:
It prints the three-dot file count alongside, so the two measurements can be compared in one output.
Building it changed what it says
The first version gave a binary verdict. Run against all four real branches, it answered "has unique content" every time — technically true, and misleading every time, since all four were right to delete.
The classification was correct; the verdict was overconfident. So it now:
merged PR for this head: #176 merged 2026-08-08→VERDICT: superseded.review, leaning superseded — 9 of 11 file(s) are identical to main or behind it.SKILL.mdcarries three real cases where "unique content" was true and deleting was still right, so the next reader calibrates against reality rather than the label.Placement
skills/here rather than staying loose in~/.agents/skills, so it gets version history, shell lint, and the discoverability check added in #182..claude/skills/branch-supersede-checksymlinks to it, and~/.agents/skills/branch-supersede-checknow points at this copy too — one source of truth reachable by both agent tools.Read-only: never checks out, merges, resets or deletes. The single network call is the PR lookup, skippable with
--no-pr.Verification
Behaviour reproduced against the two real branches it was built from: a squash-merged one classified
superseded, and a 7-of-11-identical one classifiedreview, leaning superseded. Error paths checked too — unknown ref exits 2, no argument prints usage.🤖 Generated with Claude Code