Skip to content

[Bug]: V2 storage cleanup never frees worktrees for completed/cancelled/interrupted/rolled_back threads #15146

Description

@ANSHSINGH050404

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 (024d495:apps/server/src/storageCleanup.ts:82-91). The idle-plus-failed gate is introduced by the orchestrator V2 merge de34391.

Steps to reproduce

Logic repro, no provider CLI needed:

  1. Construct an OrchestrationV2ThreadShell with branch and worktreePath set, activeRunId null, status completed, pendingBackgroundTasks [], pendingRuntimeRequest null, no queued turn.
  2. Call storageCleanupThreadIdle(thread, Date.now()).
  3. 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:

  1. Run a V2 thread to completion (status completed, no active run).
  2. Wait past worktree retention/inactivity threshold.
  3. Worktree directory remains; storage cleanup logs skip it as non-idle.

Version

upstream/main@e8545b293b, post orchestrator V2 merge de34391; 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 024d495: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

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

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions