fix(server): clean up deleted threads worktrees with subagents#23900
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.
| Evidence | Before | After |
|---|---|---|
| Existing orphan, deletion-only rule | Runtime transcript: checkout retained under native child | Runtime transcript, UI report text: 1 removed, reason Thread was deleted; directory and Git worktree registration absent |
| Revision | 200dad3b39 | ad34e6c92c |
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
- SuccessfulCodeRabbitGitHub
Review completed
- Skipped
- Skipped
- Skipped
- SkippedRemove preview downloadGitHub
- Skipped
- Skipped
- Skipped
- SuccessfulRemove preview downloadGitHub
- SkippedEAS PreviewGitHub
- SkippedBuild preview JS bundleGitHub
- SkippedDeploy web previewGitHub
- SkippedDeploy web previewGitHub
- SkippedBuild preview JS bundleGitHub
- SkippedEAS PreviewGitHub
- SuccessfulCheckGitHub
- SkippedTest WebGitHub
- Skipped
- SkippedRustGitHub
- SkippedRelease SmokeGitHub
- SuccessfulBuild and TypecheckGitHub
- SuccessfulTestGitHub
- Skipped
- SuccessfulLabel PR sizeGitHub
- SuccessfulLabel PR 23900GitHub
- Skipped
- Successful
- Successful
- SuccessfulCollect PR targetsGitHub
- SuccessfulPrepare PR size configGitHub
- SkippedEAS PreviewGitHub
- SuccessfulTest Server 4GitHub
- SuccessfulTest Server 6GitHub
- SuccessfulTest Server 1GitHub
- SuccessfulTest Server 5GitHub
- SuccessfulTest Server 8GitHub
- SuccessfulLintGitHub
- SuccessfulTest Server 3GitHub
- SuccessfulTest Server 7GitHub
- SuccessfulTest Server 2GitHub
- SuccessfulChangesGitHub
- SuccessfulNative fingerprint diffGitHub
Added 4 commits
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.
Thread transfer impact
✅ Thread transfer remains within every enforced ceiling.
| Provider | Metric | Main baseline | This PR | Impact | PR ceiling | |
|---|---|---|---|---|---|---|
| Codex | Total thread wire | 5.0 KiB | 5.0 KiB | +7 B (+0.1%) | 6.8 KiB | ✅ |
| Codex | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Codex | Live turn WebSocket wire | 1.2 KiB | 1.2 KiB | +7 B (+0.6%) | 2.0 KiB | ✅ |
| Codex | Live turn WebSocket decoded | 20.9 KiB | 20.9 KiB | 0 B (0.0%) | 29.3 KiB | ✅ |
| Codex | Live turn messages | 2 | 2 | 0 (0.0%) | 8 | ✅ |
| Claude | Total thread wire | 5.0 KiB | 5.0 KiB | +7 B (+0.1%) | 6.8 KiB | ✅ |
| Claude | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Claude | Live turn WebSocket wire | 1.2 KiB | 1.2 KiB | +7 B (+0.6%) | 2.0 KiB | ✅ |
| Claude | Live turn WebSocket decoded | 21.2 KiB | 21.2 KiB | 0 B (0.0%) | 29.3 KiB | ✅ |
| Claude | Live turn messages | 2 | 2 | 0 (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.
No actionable comments were generated in the recent review. 🎉
ℹ️ Recent review info
⚙️ Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-17812
- File: .coderabbit.config.ts
- Commit: ad34e6c
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
370e5f07-6bfe-4f69-ba52-9a0dfc7e9945
📥 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.tsapps/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.tsCleanup 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.tsCleanup 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 name Status Explanation Title check Passed The title clearly and concisely identifies the server fix for cleaning up worktrees associated with deleted threads and subagents. Description check Passed 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, … Linked Issues check Passed 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/s…Out of Scope Changes check Passed 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 … 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. ThemembersanddeletedByPathadditions 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.