You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(reaper): detect multi-commit squash-merges via GitHub merged-PR state (disk-accumulation root cause) (#1290)
* fix(reaper): detect multi-commit squash-merges via GitHub merged-PR state (disk-accumulation root cause)
The AgentWorktreeReaper's merged-check used `git cherry` (patch-id) ONLY, which
cannot detect a MULTI-commit branch that was SQUASH-merged. Since this project
squash-merges every PR, merged worktrees were kept forever and accumulated
(~118GB/290 observed), contributing to the 2026-06-26 kernel panic. Diagnosed in
the stalled 28730 session (CMT-1812), picked up here.
- New `fetchMergedPrHeadOids()` — ONE `gh pr list --state merged` call per sweep
(cached 60s, funneled through withSyncOp). Fail-safe to empty map on any error.
- `isMerged` falls back to the PR map ONLY when `git cherry` says unmerged, and
treats a worktree as merged only when its branch's merged-PR head OID EXACTLY
matches the worktree HEAD (post-merge commits are still KEPT). isClean still
independently blocks any dirty worktree.
- New config `monitoring.agentWorktreeReaper.githubMergeCheck` (default true).
Reaper still ships OFF + dry-run.
- Tests: 9 new; CLAUDE.md awareness updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(release): add Evidence section to reaper squash-merge fragment
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Instar Agent (echo) <echo@instar.local>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
"notes": "Latent blind spot in the reaper's git-cherry merged-check: it documents that multi-commit squash-merges are not detected (their per-commit patch-ids differ from the squashed commit) and conservatively KEEPS them. Because this project squash-merges every PR, merged worktrees accumulated forever (~118GB/290 observed) — a contributor to the 2026-06-26 resource-exhaustion kernel panic. Diagnosed in the stalled 28730 session (CMT-1812), picked up here."
Copy file name to clipboardExpand all lines: src/core/PostUpdateMigrator.ts
+2-1Lines changed: 2 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -5856,8 +5856,9 @@ Every guard (monitoring sentinels, reapers, the scheduler, …) is graded by wha
5856
5856
CLI-created worktrees under \`~/.instar/agents/<agent>/.worktrees/\` accumulate (each is a full source tree). The AgentWorktreeReaper reclaims ones that are **merged + clean + not-in-use** — for a merged branch the work is in main, so removing the checkout loses nothing (the branch + commits remain). It NEVER touches a worktree with uncommitted changes, an unmerged branch, a live lock, or a running process whose cwd is inside it. Ships **OFF + dry-run** (it deletes on a heuristic).
5857
5857
5858
5858
- See what's reclaimable (and why each is kept): \`curl -H "Authorization: Bearer $AUTH" http://localhost:4040/worktrees/agent-reaper\` → per-worktree verdict (in-use / uncommitted-changes / unmerged / reap-eligible) + the reclaimable count.
5859
+
- **Squash-merge detection (the accumulation fix):** the merged-check is patch-id (\`git cherry\`) FIRST — which cannot see a MULTI-commit branch that was SQUASH-merged (its commits' SHAs/patch-ids differ from the single squashed commit), so those worktrees used to pile up forever. The reaper now ALSO consults GitHub merged-PR state (ONE \`gh\` call per sweep) and treats a worktree as merged when its branch has a merged PR whose head commit EXACTLY matches the worktree's HEAD (so a branch with commits added AFTER the merge is still kept). Fail-safe: any \`gh\` error degrades to cherry-only (KEEP). Off-switch: \`{"monitoring": {"agentWorktreeReaper": {"githubMergeCheck": false}}}\`.
5859
5860
- Review the dry-run report FIRST, then enable in \`.instar/config.json\`: \`{"monitoring": {"agentWorktreeReaper": {"enabled": true, "dryRun": false}}}\`. Tune \`maxReapsPerPass\` (default 20).
5860
-
- Pairs with the Spotlight-exclusion marker (fewer worktrees = less disk AND less macOS indexing). Proactive: user asks "why is my disk full of worktrees?" / "clean up old worktrees?" → GET /worktrees/agent-reaper.
5861
+
- Pairs with the Spotlight-exclusion marker (fewer worktrees = less disk AND less macOS indexing). Proactive: user asks "why is my disk full of worktrees?" / "clean up old worktrees?" / "why is the reaper calling GitHub?" → GET /worktrees/agent-reaper; the gh call is the squash-merge detection above.
0 commit comments