Dead-session branch report is lease-scoped, so a branch no lease recorded is invisible forever #1286

Closed
opened 2026-08-26 10:38:50 +00:00 by coilyco-ops · 1 comment
Owner

What happens

reportNativeStuckLeases in aos-cli/native_shadow.go reports a branch only when it reaches that function through nativeStuckReading, and the only thing that ever calls nativeStuckReading is the loop over native session leases. A branch therefore has to satisfy all of the following to be reported:

  1. a native lease recorded it as artifact.Branch,
  2. that lease's worktree is gone from disk,
  3. the lease has expired past nativeDeadSessionGrace, and
  4. the branch is ahead of --remotes=origin.

A branch that no lease ever recorded fails at step 1 and is never reported, whatever it holds. That covers every branch made by hand, every branch made outside a native shadow, and every branch whose lease was already removed by an earlier sweep. Nothing else in the startup pass looks at local branches, so the accumulation is unbounded and silent.

Observed

A sweep of agentic-os on this host found 78 local branches. The detector had reported 13 of them. Of the remaining 65:

  • 7 held 13 commits whose patch-id is on no origin ref, entirely unreported: aos/1032-release-call-guard, aos/claude/dowel-pronouns, aos/claude/issue-refs-write-path, aos/claude/ym96-forgejo-admin, aos/claude/ym96-nine-role, aos/codex/sm89-terminal-annotation, task/bump-internal-tools.
  • 58 were fully landed and were pure litter.

Adjudicated one by one, 6 of the 7 turned out superseded and were deleted, but that was luck rather than the system working. aos/claude/issue-refs-write-path carries a real unlanded change and nothing would ever have said so.

Why the obvious fix is wrong

Reusing the existing rev-list --count <branch> --not --remotes=origin test repository-wide reports every squash-merged branch, because a squashed branch is reachable from no origin ref while carrying no work. On this checkout that test called 64 landed branches unpushed. The report has to compare by patch-id (git cherry) to say anything true on a fleet whose default merge style is squash.

Fix

Add a repository-wide orphan-branch reading beside reportNativeResidentDrift, which already walks every resident repository in runNativeWorkspaceSweep. A branch is reported when it is not main, is held by no worktree and no live lease, has no refs/remotes/origin/<branch> counterpart, and has at least one commit git cherry origin/main marks +. Gate the patch-id walk behind the cheap rev-list count so a clean fleet pays almost nothing.

Note on scope

The lease-scoped behaviour is correct for what that function documents ("A purged worktree whose branch holds local-only commits is preserved forever, correctly. Silence about it is the defect"). This is a second reading beside it rather than a change to it.

## What happens `reportNativeStuckLeases` in `aos-cli/native_shadow.go` reports a branch only when it reaches that function through `nativeStuckReading`, and the only thing that ever calls `nativeStuckReading` is the loop over native session leases. A branch therefore has to satisfy all of the following to be reported: 1. a native lease recorded it as `artifact.Branch`, 2. that lease's worktree is gone from disk, 3. the lease has expired past `nativeDeadSessionGrace`, and 4. the branch is ahead of `--remotes=origin`. A branch that no lease ever recorded fails at step 1 and is never reported, whatever it holds. That covers every branch made by hand, every branch made outside a native shadow, and every branch whose lease was already removed by an earlier sweep. Nothing else in the startup pass looks at local branches, so the accumulation is unbounded and silent. ## Observed A sweep of `agentic-os` on this host found 78 local branches. The detector had reported 13 of them. Of the remaining 65: * 7 held **13 commits whose patch-id is on no origin ref**, entirely unreported: `aos/1032-release-call-guard`, `aos/claude/dowel-pronouns`, `aos/claude/issue-refs-write-path`, `aos/claude/ym96-forgejo-admin`, `aos/claude/ym96-nine-role`, `aos/codex/sm89-terminal-annotation`, `task/bump-internal-tools`. * 58 were fully landed and were pure litter. Adjudicated one by one, 6 of the 7 turned out superseded and were deleted, but that was luck rather than the system working. `aos/claude/issue-refs-write-path` carries a real unlanded change and nothing would ever have said so. ## Why the obvious fix is wrong Reusing the existing `rev-list --count <branch> --not --remotes=origin` test repository-wide reports every squash-merged branch, because a squashed branch is reachable from no origin ref while carrying no work. On this checkout that test called 64 landed branches unpushed. The report has to compare by **patch-id** (`git cherry`) to say anything true on a fleet whose default merge style is squash. ## Fix Add a repository-wide orphan-branch reading beside `reportNativeResidentDrift`, which already walks every resident repository in `runNativeWorkspaceSweep`. A branch is reported when it is not `main`, is held by no worktree and no live lease, has no `refs/remotes/origin/<branch>` counterpart, and has at least one commit `git cherry origin/main` marks `+`. Gate the patch-id walk behind the cheap `rev-list` count so a clean fleet pays almost nothing. ## Note on scope The lease-scoped behaviour is correct for what that function documents ("A purged worktree whose branch holds local-only commits is preserved forever, correctly. Silence about it is the defect"). This is a second reading beside it rather than a change to it.
Author
Owner

Landed as bb663697 via #1287. All four CI checks green.

The report is now a second reading beside reportNativeResidentDrift rather than a change to the lease path, as scoped above. TestASquashMergedBranchIsNotAnOrphan is the negative control for the patch-id decision: swapping the implementation back to the reachability count makes it fail, verified by mutation.

Run against this repository the new reading returns exactly one branch, aos/claude/issue-refs-write-path, with no false positives from main or the six live session worktrees.

Landed as `bb663697` via https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/pulls/1287. All four CI checks green. The report is now a second reading beside `reportNativeResidentDrift` rather than a change to the lease path, as scoped above. `TestASquashMergedBranchIsNotAnOrphan` is the negative control for the patch-id decision: swapping the implementation back to the reachability count makes it fail, verified by mutation. Run against this repository the new reading returns exactly one branch, `aos/claude/issue-refs-write-path`, with no false positives from `main` or the six live session worktrees.
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
coilyco-flight-deck/agentic-os#1286
No description provided.