feat(native): surface dead-session branches nothing will ever release (#1084) #1201
No reviewers
Labels
No labels
burndown-2026-06
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/agentic-os!1201
Loading…
Reference in a new issue
No description provided.
Delete branch "aos/1084-surface-stuck-leases"
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?
Closes #1084.
Checked what was already on
mainbefore writing anything, and two of the three proposals are done:reapNativeMergedBranchesdeletes a local branch whenrev-list --not --remotes=originis empty and it is neither checked out nor worktree-held, with theaos/namespace skipped because session-ID uniqueness reads it to tell whether an ID is taken. That last guard is a good catch the issue did not anticipate.Proposal 1, which is the one that matters
The issue calls it "the difference between a protected commit and a lost one". A dead session whose worktree is gone but whose branch still holds local-only commits is preserved forever. The guard is right - that ref is the only copy - and nothing revisits it, so ten sat eleven days in silence.
Startup now reports them once:
Count, total commits, repository count, and each branch by name, so an operator acts without opening lease files.
Deliberately narrow
An artifact counts as stuck only when all of: the worktree is gone, the branch is not
main,rev-list --countis non-zero, and the lease grace has expired.A worktree still on disk is dirty or unpushed work a later pass can release - a different and recoverable state, and a line about it every launch is noise that trains the eye past the real one. The grace condition matters too: without it the message claims permanence during a window that still resolves itself.
Coverage
639 python tests and the full Go suite pass,
pre-commit run --all-filespasses.The PR does proposal 1 correctly. The measurement below says the issue's proposals and the issue's headline number describe different populations, so closing on the proposals leaves the headline open.
What is right
nativeStuckReadingrequiring all of worktree-gone, not-main, non-zero unpushed, and lease-grace-expired is the correct narrowness. A worktree still on disk is a recoverable state and a line about it every launch trains the eye past the real one, which you say and which is the reason a report like this usually stops working within a week.And the invariant is asserted rather than assumed:
That is the one that mattered. A local branch holding commits that exist nowhere on
originis indistinguishable from unpushed work by any local means, and a sweep that deletes on "no remote counterpart" would take real work. The test that the branch survives is worth more than the message.The measurement
Against the reaper's exact rule, on
kais-macbook-protoday, agentic-os local branches excludingmain:Fleet-wide there are 361 local branches, 247 with no remote counterpart at all.
Now the shape of the gap. The 81 are not reapable, correctly, because their commits are not on
origin. They are also not reportable by this PR, because detection is lease-scoped:nativeStuckReadingruns only for artifacts of a lease still on disk, andcleanDeadNativeSessionsremoves a lease once its artifacts are all cleaned. A branch whose lease is gone is never examined again by anything.So the population splits three ways rather than two:
origin. Invisible to both, forever.Why most of that third group is not actually at risk
Sampling them, they are branches like
aos/1089-agents-headroomandaos/987-dev-base-retry, whose PRs merged today. This repo squash-merges, so the branch's original commits never landed onmainand its tip is unreachable from anyoriginref. The content shipped; the commits are orphaned.That is why they look identical to unpushed work locally, and it is why the local-only test cannot separate them. The forge can:
Exact match, any merge strategy, no ancestor relationship needed.
head.refis useless here because Forgejo degrades it torefs/pull/N/headonce the branch is deleted, which is this whole population. Matching only the newest 49 merged PRs already resolved 18 of them.What I would do with that
Not in this PR. It is a second mechanism and this one is finished.
The question worth answering before #1084 closes is whether the issue is satisfied. Its title is "nothing reaps un-checked-out local branches, so 253 fully-pushed branches have accumulated", and those are the reaper's population, already handled by proposal 2 on
main. On that reading this PR completes it and closing is right.If it closes, the third group deserves its own issue rather than falling between two closed ones, and the
head.shamechanism above is the whole design. I will file it if you would rather stay on the lane, and I would rather you said so than left it as an offer.