From b8eb598329594749f7b1086d607fe21a130b94be Mon Sep 17 00:00:00 2001 From: damocles Date: Fri, 28 Aug 2026 17:09:38 +0200 Subject: [PATCH] =?UTF-8?q?hive-forge:=20fix=20stale-branches=20comment/do?= =?UTF-8?q?cs=20=E2=80=94=20hyperhive=20rebase+ff=20merges,=20not=20squash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/base/skills/forge-triage/SKILL.md | 12 ++++++------ hive-forge/src/verbs/lint.rs | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/claude-plugins/plugins/base/skills/forge-triage/SKILL.md b/claude-plugins/plugins/base/skills/forge-triage/SKILL.md index a0a438cd..267f0d20 100644 --- a/claude-plugins/plugins/base/skills/forge-triage/SKILL.md +++ b/claude-plugins/plugins/base/skills/forge-triage/SKILL.md @@ -31,12 +31,12 @@ dimension directly. - **Stale branches** - `hive-forge lint stale-branches --days ` finds remote branches with no recent commits (skips branches that are heads of open PRs) and reports each one's merge outcome (PR merged / - closed unmerged / no PR at all) — squash-merge ancestry can't tell - those apart, so don't delete a stale branch on the age alone; check - the verdict first. On a repo with enough PRs to exceed the verb's own - page cap, an old branch's outcome may come back "unknown" instead of - a verdict — that's not the same claim as "no PR", treat it as - "can't tell, don't delete" too. + closed unmerged / no PR at all) — hyperhive's rebase+ff merges mean + ancestry can't tell those apart, so don't delete a stale branch on the + age alone; check the verdict first. On a repo with enough PRs to + exceed the verb's own page cap, an old branch's outcome may come back + "unknown" instead of a verdict — that's not the same claim as "no PR", + treat it as "can't tell, don't delete" too. ## Using them as a sweep diff --git a/hive-forge/src/verbs/lint.rs b/hive-forge/src/verbs/lint.rs index b85e1805..00aee08c 100644 --- a/hive-forge/src/verbs/lint.rs +++ b/hive-forge/src/verbs/lint.rs @@ -286,9 +286,11 @@ fn run_stale_branches(client: &Client, args: StaleBranchesArgs) -> Result<()> { // a closed one tells a surviving stale branch its actual fate — // merged (branch is a leftover copy, safe to delete) vs. closed // unmerged / never had a PR (the branch is the only copy). Because - // hyperhive squash-merges, a merged branch's tip is never an - // ancestor of main, so ancestry can't tell these apart; this is the - // only signal that can. + // hyperhive merges via rebase + fast-forward, the branch's commits + // are replayed onto main's current tip as new commits before main + // moves — so the original branch tip's SHA is never an ancestor of + // main even once merged, and ancestry can't tell these apart; this + // is the only signal that can. // Whether the walk below hit `MAX_PAGES` without ever seeing a // short page — i.e. there are more PRs than the cap fetched, so // `latest_pr_by_head` is missing an unknown number of the oldest