[Bug]: V2 storage cleanup never frees worktrees for completed/cancelled/interrupted/rolled_back threads
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- typescript
- Domain
- backend
Research direction
Start with storageCleanupThreadIdle in apps/server/src/storageCleanup.ts:83-92, then inspect its call sites at :220 and :317 and the status definitions and projection in packages/contracts/src/orchestrationV2.ts and apps/server/src/orchestration-v2/ProjectionStore.ts. Verify terminal V2 threads with activeRunId null and satisfied background or queued guards become eligible for cleanup, while active work remains protected; the issue notes that the targeted vpr test run failed due to runner configuration.
Written by the indexing model from the issue text.
Description
What happened
V2 threads that finish as completed/cancelled/interrupted/rolled_back keep their worktrees forever. storageCleanupThreadIdle only returns true for status idle or failed, so any thread whose shell status mirrors a terminal run status other than failed is never eligible for worktree cleanup. Disk usage grows unboundedly, especially on remote servers.
Diagnosis
Grounded in source at upstream/main@e8545b293b:
- packages/contracts/src/orchestrationV2.ts:445-456 OrchestrationV2RunStatus includes preparing, queued, starting, running, waiting, completed, interrupted, failed, cancelled, rolled_back.
- packages/contracts/src/orchestrationV2.ts:1661-1664 OrchestrationV2ShellThreadStatus is idle plus RunStatus, so thread.status can be completed/interrupted/cancelled/rolled_back.
- apps/server/src/orchestration-v2/ProjectionStore.ts:1485-1499 shellStatusFromStoredRunStatus mirrors latest_run_status verbatim, including completed/interrupted/cancelled/rolled_back.
- apps/server/src/storageCleanup.ts:83-92 storageCleanupThreadIdle requires thread.activeRunId === null AND (status === idle OR status === failed). Terminal threads with status completed/cancelled/interrupted/rolled_back and activeRunId null fail the predicate and are skipped at :220 and :317.
V1 allowed cleanup whenever session was null/stopped and latestTurn was not running, regardless of terminal state (024d49520e:apps/server/src/storageCleanup.ts:82-91). The idle-plus-failed gate is introduced by the orchestrator V2 merge de3439142.
Steps to reproduce
Logic repro, no provider CLI needed:
- Construct an OrchestrationV2ThreadShell with branch and worktreePath set, activeRunId null, status completed, pendingBackgroundTasks [], pendingRuntimeRequest null, no queued turn.
- Call storageCleanupThreadIdle(thread, Date.now()).
- Result is false, so the worktree candidate is filtered out. Same for cancelled, interrupted, rolled_back. Only idle and failed return true.
Observable product repro:
- Run a V2 thread to completion (status completed, no active run).
- Wait past worktree retention/inactivity threshold.
- Worktree directory remains; storage cleanup logs skip it as non-idle.
Version
upstream/main@e8545b293b, post orchestrator V2 merge de3439142; checked 2026-10-03.
Environment
Windows x64 repo checkout, verified via git show upstream/main. Server-side defect, applies on any OS/host, especially remote servers with many finished threads.
Evidence
- apps/server/src/storageCleanup.ts:83-92 predicate, :220 and :317 call sites
- packages/contracts/src/orchestrationV2.ts:445-456 RunStatus, :1661-1664 ShellThreadStatus
- apps/server/src/orchestration-v2/ProjectionStore.ts:1485-1499 status mirroring
- V1 baseline 024d49520e:apps/server/src/storageCleanup.ts:82-91
Focused verification via git show upstream/main only; no repo-wide lint/typecheck per repo rules. Targeted vpr test run failed on runner config in this checkout.
Related issues
- #14742 merged-worktree cleanup retains worktrees after squash merges - merge-detection, not idle-predicate gating. Not duplicate.
- #14843 retains upstream-merged branches in fork checkouts - fork sync scope. Not duplicate.
- #13836 t3.json Setup Worktree action never cleaned - setup-action scope. Not duplicate.
- #14966 deleting thread leaves preview sessions - PreviewManager scope. Not duplicate.
- Searched open issues for storageCleanupThreadIdle, worktree leak, idle failed: no match for this predicate.
Fix applied or workaround
None. Possible direction: treat terminal statuses completed/cancelled/interrupted/rolled_back as idle-eligible once activeRunId is null and background/queued guards pass, or add explicit terminal-state handling with inactivity clock. Not tested.
Filed by
opencode (muse-spark-1.3-contributor-free) via audit session
- Dominant language
- TypeScript
- Stars
- 24.4k
- Forks
- 6.4k
- Avg merge
- 10h 48m
- Merged PRs (30d)
- 215
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from pingdotgg/t3code
-
bug via-triage
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
pingdotgg/t3code#15221 · 1 comment ·
Maintainers usually reply within 1 day
-
bug via-triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
pingdotgg/t3code#15161 · 1 comment ·
Maintainers usually reply within 1 day
-
bug good first issue via-triage
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
pingdotgg/t3code#15159 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
bug needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
All issues in pingdotgg/t3code
Similar issues
-
type/bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 95/100
lingdojo/kana-dojo#31593 · 1 comment · 5 reactions ·
Maintainers usually reply within 1 day
-
bug
Difficulty 1/5 1-3 hours Newbie friendliness 90/100
apache/fineract-backoffice-ui#697 ·
Maintainers usually reply within 1 day
-
good first issue hacktoberfest help wanted
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
libredb/libredb-studio#1291 · 1 comment ·
Maintainers usually reply within 1 day
-
bug P1
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Yeachan-Heo/gajae-code#6295 · 1 comment ·
Maintainers usually reply within 1 day