feat(bin): prune gone branches during fleet sync - #20
Conversation
fm-fleet-sync now fetches with --prune and deletes local branches whose upstream tracking branch is gone and that have no worktree, so merged feature branches stop piling up in the pooled clones. It never touches the checked-out branch or a branch with a live worktree, so it cannot discard unlanded work; FM_FLEET_PRUNE=0 disables it. Widens the fleet-sync hard-rule exception and updates the docs to match.
The merge-base --is-ancestor gate makes pruning a permanent no-op in this fleet: PRs are squash-merged (the firstmate repo only allows squash), so a merged branch is never an ancestor of origin/<default> and nothing is ever pruned. Reproduced with a squash-merge clone. Pruning now relies on the gone + no-worktree pair, which already proves the work landed - teardown removes a branch's worktree only after the work reached the remote - so it stays safe without the ancestor check. Docs updated to match.
|
Audited against code: all four slices implemented and tested (layered hued equipment render, gender-gated beards, partial-hue cloth-dye shader, splash pickers + live preview reusing the real sprite stack). Registry counts meet/exceed the PRD; full suite green (490 tests). Remaining work is the cross-cutting UO-client art bake the PRD itself flagged, not a missing slice. Closing as delivered. |
* feat(bin): prune gone branches during fleet sync fm-fleet-sync now fetches with --prune and deletes local branches whose upstream tracking branch is gone and that have no worktree, so merged feature branches stop piling up in the pooled clones. It never touches the checked-out branch or a branch with a live worktree, so it cannot discard unlanded work; FM_FLEET_PRUNE=0 disables it. Widens the fleet-sync hard-rule exception and updates the docs to match. * no-mistakes(review): Safely prune only merged gone branches * no-mistakes(document): Document fleet pruning behavior * fix(bin): prune squash-merged gone branches, drop ancestor gate The merge-base --is-ancestor gate makes pruning a permanent no-op in this fleet: PRs are squash-merged (the firstmate repo only allows squash), so a merged branch is never an ancestor of origin/<default> and nothing is ever pruned. Reproduced with a squash-merge clone. Pruning now relies on the gone + no-worktree pair, which already proves the work landed - teardown removes a branch's worktree only after the work reached the remote - so it stays safe without the ancestor check. Docs updated to match. * no-mistakes(document): Sync fleet-prune documentation
Scout plan (huddle-app second mate, 2026-08-29)Proposed Options / Plan / Blocking / Lead decisions for this ticket, from Current state
Options
Recommended PlanTen years on, the review page still shows the exact source and a repeatable Huddle presentation without becoming either a prompt store or a second Huddle client. The future engineer is glad that adding a state is data, not a new page. Modules
Seams
Validation criteria
Blocking?non-blocking. The one-page generator, static Huddle states, expected-return notes, and Lavish review loop can ship now. #39 and #44 later add their source-model entries to the same page; they do not justify a second review surface. Lead decisionsNone. The page path, generated/static posture, review command, required Huddle presentation, and evidence boundary are recorded. Exact future section/module contents remain with #39 and #44. |
Intent
Port the one firstmate-shaped idea from the EveryInc compound-engineering skills the captain reviewed: fold a gone-branch prune into the EXISTING bin/fm-fleet-sync.sh (captain said fold into existing scripts, every new script is overhead - deliberately NOT a new script). Behavior: fm-fleet-sync fetches with --prune, then deletes local branches whose upstream tracking branch is gone (remote branch deleted = its PR merged), but only when safe - never the checked-out branch, never a branch that still has a worktree. SAFETY MODEL (important, do not 'fix' this): pruning relies on the 'gone + no worktree' pair, NOT on a merge-base --is-ancestor check. This is deliberate. This fleet squash-merges exclusively (the firstmate repo only allows squash merges; merge commits and rebase merges are disabled), and under a squash merge a merged branch is NEVER an ancestor of origin/ - so an ancestor gate would prune nothing at all. I reproduced exactly that: with an --is-ancestor gate the squash-merged branch is left behind; without it, it is correctly pruned, while a gone branch that still has a worktree is always kept. The no-worktree guard IS the real safety net: firstmate's teardown removes a branch's worktree only after confirming the work reached the remote, so 'gone + no worktree' already proves the work landed and nothing unlanded is ever discarded. A previous run of this very pipeline added the --is-ancestor gate; I removed it with that reproduction as evidence, so please do not reintroduce it. FM_FLEET_PRUNE=0 disables pruning. Because pruning widens one of firstmate's three sanctioned 'never write to a project' exceptions, AGENTS.md's prime-directive wording plus the README, bootstrap, and teardown descriptions were updated to match - that doc churn is intentional. Validated against constructed clones: squash-merged gone branch pruned, gone+worktree branch kept, non-gone default kept, FM_FLEET_PRUNE=0 respected.
What Changed
fm-fleet-sync.shto fetch with--pruneand delete local branches whose upstream is gone when they are not checked out and have no linked worktree.FM_FLEET_PRUNE=0as an escape hatch to disable branch pruning while preserving the existing fleet fetch and safe default-branch fast-forward behavior.Risk Assessment
✅ Low: The change is limited to one fleet-sync helper plus matching docs, with pruning guarded by fetch success, gone upstream state, current-branch exclusion, and worktree exclusion.
Testing
Inspected the changed shell/docs, then exercised the user-facing
bin/fm-fleet-sync.shCLI against constructed clones that model squash-merged gone branches, linked worktree safety, checked-out branch safety, and theFM_FLEET_PRUNE=0opt-out; all assertions passed and the worktree stayed clean.Evidence: Fleet prune end-to-end transcript
Showssquash-gonepruned despite not being an ancestor oforigin/main,kept-worktreeretained due to a linked worktree,current-goneretained because it is checked out, andoptout-goneretained withFM_FLEET_PRUNE=0.Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
git status --short && git diff --stat a16660de607e52829a075baa81095049d4bbf02a..HEADInspectedbin/fm-fleet-sync.sh,bin/fm-bootstrap.sh,bin/fm-teardown.sh,AGENTS.md, andREADME.mdfor the changed behavior and docs.Created local bare remotes and clones under/var/folders/5x/4nqprlbx0518k3ybcb1sz6gr0000gn/T/no-mistakes-evidence/01KV4VTKWG2T1GWHNK2P4ST3VR/fleet-prune-e2e, then ranbin/fm-fleet-sync.sh <constructed-project>to verify a squash-merged gone branch is pruned without an ancestor check, a gone branch with a linked worktree is retained, a checked-out gone branch is retained, andmainremains present.RanFM_FLEET_PRUNE=0 bin/fm-fleet-sync.sh <constructed-project>to verify pruning is disabled while fetch still marks the upstream as gone.git status --short✅ **Document** - passed
✅ No issues found.
.github/workflows/ci.yml:18- Configured shell lint commandshellcheck bin/*.shcould not be run becauseshellcheckis not installed in this environment.✅ **Push** - passed
✅ No issues found.