fix(server): clean up deleted threads worktrees with subagents#23900

merged4
main
fix/issue-17812
opened1d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1d ago

Problem

With only Delete worktrees with deleted threads enabled, deleting a thread that used a subagent leaves its worktree behind. Reproduced on Linux in the web app with a completed Codex native subagent: cleanup attributed the checkout to the hidden child and kept it after the parent was deleted.

Change

Recognize a deleted thread as the worktree owner when its remaining users form its subagent chain and its project's deletion cleanup rule is enabled. Apply the existing activity, settle grace, sharing, and final revalidation checks to those children. This also releases existing orphaned worktrees while preserving other cleanup rules when deletion cleanup is off.

Scope and approval

Fixes #17812

Triaged bug via the automated issue flow: #17812.

Verification

  • Red-first regression: native-child case failed with kept / Has commits beyond the default branch; no-child control passed. Red test record.
  • vp test run apps/server/src/storageCleanup.test.ts: 122 passed, including deletion-off age cleanup and subagent settle grace; rerun after merging main.
  • Scoped lint on both changed files and server tsc --noEmit -p .: passed.
  • Two independent reviewers returned MERGE after the follow-up correction; proof audit returned SUFFICIENT.
EvidenceBeforeAfter
Existing orphan, deletion-only ruleRuntime transcript: checkout retained under native childRuntime transcript, UI report text: 1 removed, reason Thread was deleted; directory and Git worktree registration absent
Revision200dad3b39ad34e6c92c

Server-only change; render fixture matrix is empty. Runtime verification used the real web client against isolated state. The copied fixture's divergent migration metadata was repaired before running current main; thread and event data were preserved, as disclosed in the transcript. No platform-specific code changed.

Models: GPT-6.1-Sol (Codex harness) and Claude Opus 5.5 (Claude Agent harness), orchestrated through T3 Code.

Checks

All checks passed

Added 4 commits

  • test(server): reproduce issue 178128b787b7
  • Merge remote-tracking branch 'origin/main' into fix/issue-17812ad34e6c
  • fix(server): deleting a thread now cleans the worktree its subagents sharedcb5e876
  • fix(server): live cleanup rules still apply when deletion cleanup is offeb37b7e
Synced from GitHub

Approvability

Verdict: Approved at ad34e6c

Macroscope's review found this PR approvable — This focused server fix corrects worktree ownership for deleted threads with native subagents while preserving existing cleanup settings and revalidation safeguards. Regression tests cover deletion-enabled, deletion-disabled, and settle-grace scenarios; product defaults remain unchanged.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB+7 B (+0.1%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB+7 B (+0.6%)2.0 KiB✅
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB+7 B (+0.1%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB+7 B (+0.6%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB0 B (0.0%)29.3 KiB✅
ClaudeLive turn messages220 (0.0%)8✅

Baseline: 23bd753 · PR result: ad34e6c · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 23bd753806eb9db5a315fbf9ac6563d355f20b3a and ad34e6c92ce601be54aff7c5c22901c8100503e9.

📒 Files selected for processing: 2
  • apps/server/src/storageCleanup.test.ts
  • apps/server/src/storageCleanup.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

📝 Walkthrough

Storage cleanup now evaluates a deleted thread and its surviving subagents as a shared worktree group. It applies idle and settled-grace checks to live group members and revalidates ownership and activity before removal. Tests cover cleanup settings and recently settled subagents.

Changes: Deleted-thread worktree cleanup

Layer / File(s)Summary
Deleted owner candidate selection
apps/server/src/storageCleanup.ts
Cleanup can select a deleted thread as the worktree owner when deletion cleanup is enabled and the deleted thread owns the shared subagent chain.
Cleanup checks and regression cases
apps/server/src/storageCleanup.ts, apps/server/src/storageCleanup.test.ts
Cleanup applies idle and settled-grace checks to surviving subagents and revalidates group ownership and activity. Tests cover deletion cleanup enabled and disabled, including a recently settled subagent.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: maria-rcks

Merge Risk: ⚪ Minimal · up to ad34e

No actionable merge-blocking issue was established for deleted-thread worktree cleanup. The change is ready for normal merge checks.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely identifies the server fix for cleaning up worktrees associated with deleted threads and subagents.
Description checkPassedThe description includes complete Problem, Change, Scope and approval, and Verification sections. It links the related issue, explains the server-only scope, reports focused test and runtime results, …
Linked Issues checkPassedRequirement [#17812]: with "Delete worktrees with deleted threads" enabled, a deleted thread's worktree must be removed even when its subagent threads remain. The diff implements this in apps/server/s…
Out of Scope Changes checkPassedAll changes are in apps/server/src/storageCleanup.ts and apps/server/src/storageCleanup.test.ts. Each hunk maps to the issue. The worktreeOwner generic widening lets deleted threads, which carry only …
Full details: Description check

Explanation

The description includes complete Problem, Change, Scope and approval, and Verification sections. It links the related issue, explains the server-only scope, reports focused test and runtime results, and discloses verification limitations.

Full details: Linked Issues check

Explanation

Requirement [#17812]: with "Delete worktrees with deleted threads" enabled, a deleted thread's worktree must be removed even when its subagent threads remain. The diff implements this in apps/server/src/storageCleanup.ts. Candidate selection now picks a deleted thread as owner when its project has worktreeOnDelete enabled and worktreeOwner([deleted, ...group]) returns that thread. Previously, live subagents on the path blocked the deleted thread. The final revalidation no longer blocks deleted candidates when remaining members still share the worktree. Remaining subagents must pass the same idle, settle-grace, branch, and local-change checks as other candidates. The new tests in storageCleanup.test.ts cover: a deleted thread with no subagents (removed); a deleted thread with one completed native subagent (removed, reason "Thread was deleted", directory absent); a deleted thread whose subagent settled at the current time (kept, "Settled moments ago"); and deletion cleanup off with a remaining subagent (live inactivity rule applies). Residual gaps: the issue's two-subagent case (child-1 and child-2) is not a new test. The code path should handle it because both children share the deleted parent as the single top of the chain, but I did not read the full worktreeOwner body, so this is inferred. The issue's web delete-prompt concern (apps/web/src/worktreeCleanup.ts) is not changed. The issue reports it from code reading only, untested, and the PR states it is server-only. I did not run the test suite. Assessment relies on the diff and test diff.

Full details: Out of Scope Changes check

Explanation

All changes are in apps/server/src/storageCleanup.ts and apps/server/src/storageCleanup.test.ts. Each hunk maps to the issue. The worktreeOwner generic widening lets deleted threads, which carry only id and lineage, be passed to the same ownership logic. The candidate selection hunk adds deleted-owner selection for shared subagent chains. The !deleted && removals apply idle and settle-grace checks to deleted candidates' subagents, as the issue requires. The revalidation hunk moves the latest-state check out of the else branch so that deleted candidates are checked too. The members and deletedByPath additions support those changes. The test fixture changes (deleted thread storage and setDeletedThreads) support the new tests. The deletion-off path keeps the live owner and the previous rules, as the PR states. No unrelated files or behavior changes appear in the diff.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.