fix(server): completed subagents no longer block their parent's file revert#31877
Problem
A thread working in its own worktree could not use Edit from here → Revert files too once one of its subagents had finished. The restore-isolation check counted the finished subagent, which keeps the parent's worktree path, as another owner of that worktree, and refused with "File restore requires an isolated worktree." This happened for Claude Task subagents and for delegate_task children with shared isolation.
Reproduction on main 291bcc392c, in the web app with a fresh database and a synthetic repo: start a thread in a new worktree, let it edit a file, then have it run one Claude Task subagent (or one delegate_task child, isolation shared) that edits the file. Edit from here → Revert files too on the second message is rejected, and the file stays as it was. A control thread whose two turns edited the file itself reverts fine.
Change
isCheckpointRestoreIsolated now skips another thread only when all of these hold:
- it descends from the restoring thread through
subagentlinks only; - it uses exactly the same worktree path;
- it is not live: no active run, activity, pending request or background work;
- every subagent record its parent keeps for it is
completed. Native children have no runs of their own, so this is where their completion is recorded; - none of its own runs is unfinished, including a held queued follow-up, which the shell leaves out of its status.
Everything else still blocks as before: running or waiting children, children that failed or were interrupted, forks, side chats with tool activity, unrelated threads, and another thread's subagents. Both rollback admission and execution use this helper.
The user guide's description of when file restore is refused now says that completed subagents don't count.
Scope and approval
Fixes pingdotgg/t3code#31865
Verification
vp test run apps/server/src/orchestration-v2/CheckpointRestoreSafety.test.ts: 19 passed. The new table fails on main for a completed subagent and a completed sub-subagent. A further row, a finished native subagent whose shell status isidle, fails on a shell-status-only version of the rule. The blocking rows also pass: running native subagent, running subagent, subagent awaiting approval, subagent with background work, completed subagent with a held queued follow-up, and another thread's subagent. The held-queue row fails if the runs check is removed.vp run check:changedpasses (format, lint, knip, typecheck, tests).- Runtime check in the web dev server, fresh database, synthetic repo:
| Thread | Children in the parent's worktree | main 291bcc392c | this branch |
|---|---|---|---|
| parent | one Claude Task subagent, finished | rejected ("File restore requires an isolated worktree…"), file unchanged | accepted, conversation rewound, file restored to the target checkpoint |
| delegator | one delegate_task child, isolation shared, finished | rejected the same way, file unchanged | accepted, file restored |
| control | none | accepted, file restored | unchanged |
Driver used for the runtime check (scratch, not committed)
| 1 | REPO=$SCRATCH/repo; B=$CHECKOUT/.t3 |
| 2 | git init -q -b main "$REPO" && printf 'hello\n' > "$REPO/notes.txt" && git -C "$REPO" add . && git -C "$REPO" commit -qm init |
| 3 | cd "$CHECKOUT/apps/server" |
| 4 | node src/bin.ts project add "$REPO" --base-dir "$B" |
| 5 | node src/bin.ts thread start "$REPO" "Append the line 'turn one' to notes.txt. Do nothing else and reply 'done'." \ |
| 6 | --title parent --provider claudeAgent --model <model> --worktree main --branch repro-parent --wait --base-dir "$B" |
| 7 | node src/bin.ts thread send <parent id> "Use the Task tool to launch exactly one general-purpose subagent, in the foreground, with this prompt: 'Append the line turn two from subagent to notes.txt in the current directory, then reply done.' Do not edit any file yourself." --wait --base-dir "$B" |
| 8 | # delegator: the same, with "Call the T3 MCP tool delegate_task exactly once with mode 'wait', isolation 'shared', and task: ..." |
| 9 | # control: two turns that append to notes.txt directly |
| 10 | # Then in the web client: expand the second message, Edit from here → Revert files too, and read notes.txt in the thread's worktree. |
Not checked: desktop and mobile clients (the change is server-only and the clients call the same rollback RPC), and providers other than Claude for native subagents (the rule reads provider-neutral subagent records). Screenshots were taken but not attached because the upload tool was unavailable on the verification machine; the table above is the observed result.
AI-assisted; verified with the tests and tools listed above.
Checks
Added 7 commits
- fix(server): finished native subagents no longer block their parent's file revert38e5672
- docs: finished subagents no longer block Revert files too4a94cac
- Merge remote-tracking branch 'origin/main' into fix/issue-3186563b5730
- test(server): reproduce #31865 completed subagents blocking file restore65b6714
- fix(server): completed subagents no longer block their parent's file revert99e884a
- fix(server): a held queued follow-up on a subagent still blocks its parent's file revertb6e6f00
- docs: say completed subagents, since failed or interrupted ones still blocke4000e2
Approvability
Verdict: Approved at e4000e2
Macroscope's review found this PR approvable — Completed subagent descendants no longer block their parent's requested file restore, and their edits revert with the parent's. The exception requires verified completion and a shared worktree; protections for unrelated threads 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 | 0 B (0.0%) | 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 | 0 B (0.0%) | 2.0 KiB | ✅ |
| Codex | Live turn WebSocket decoded | 21.5 KiB | 21.5 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Codex | Live turn messages | 1 | 1 | 0 (0.0%) | 8 | ✅ |
| Claude | Total thread wire | 5.0 KiB | 5.0 KiB | 0 B (0.0%) | 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 | 0 B (0.0%) | 2.0 KiB | ✅ |
| Claude | Live turn WebSocket decoded | 21.9 KiB | 21.9 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Claude | Live turn messages | 1 | 1 | 0 (0.0%) | 8 | ✅ |
Baseline: 2756da4 · PR result: e4000e2 · 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.
Walkthrough
-
The restore-isolation check now allows file restoration when same-worktree subagent descendants meet completion and liveness conditions. Tests cover descendant lineage and activity states. The composer documentation describes how completed subagent edits are reverted with the thread.
Changes: Restore isolation
Layer / File(s) Summary Descendant eligibility checks
apps/server/src/orchestration-v2/CheckpointRestoreSafety.tsThe helper checks subagent ancestry across active and archived threads. It defines preparing,queued,starting,running, andwaitingas unfinished run statuses.Owner scan and regression coverage
apps/server/src/orchestration-v2/CheckpointRestoreSafety.ts,apps/server/src/orchestration-v2/CheckpointRestoreSafety.test.ts,docs/user/composer.mdThe owner scan skips same-worktree descendants only when the subagent records are completed and the descendant has no active run, live subagent shell, or unfinished run. Tests cover lineage and activity cases. The documentation states that completed subagent edits are reverted with the thread. Estimated code review effort: 2 (Simple) | ~12 minutes
Change: Bug fix · Severity of issue fixed: Medium
Suggested reviewers:
t3dotgg
Merge Risk: External image Minimal · up to e4000
-
This change lets a parent thread revert files when its completed subagents share the same worktree, while running, queued, forked and unrelated threads still block the revert. No merge-blocking risk was found in the supplied context.
Pre-merge checks: Passed 4
-
Check name Status Explanation Title check Passed The title clearly describes the main change. Description check Passed The description covers the problem, change, scope, and verification. It links an issue, but does not establish whether it is triaged. It also omits the model and harness used for AI assistance. Linked Issues check Passed [ #31865] The isolation check skips only same-worktree descendants with strict subagent ancestry, completed parent records, no live shell or active run, and no unfinished runs. It also checks archived …Out of Scope Changes check Passed [ #31865] The safety-check changes, regression tests, and user guide update support the requested restore behavior. The changes do not add the excluded shared-workspace restore or rollback error wordin…Full details: Linked Issues check
-
Explanation
[
#31865] The isolation check skips only same-worktree descendants with strict subagent ancestry, completed parent records, no live shell or active run, and no unfinished runs. It also checks archived threads. Other owners retain the existing isolation checks. The helper remains in use at admission and execution. Automated tests cover completed children and grandchildren, native children, active or waiting children, background work, queued runs, and unrelated subagents.
Full details: Out of Scope Changes check
-
Explanation
[
#31865] The safety-check changes, regression tests, and user guide update support the requested restore behavior. The changes do not add the excluded shared-workspace restore or rollback error wording work.
-
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
External image Recent review info
-
External image Run configuration
-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-31865
- File: .coderabbit.config.ts
- Commit: e4000e2
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
b3431e79-180a-4adb-826b-54b0fba6a23b
External image Commits
-
Reviewing files that changed from the base of the PR and between 2756da402b5d795baa05762cba1706a2c0e2fac8 and e4000e221bf7633bc6eb9258379fd2436ff7894e.
External image Files selected for processing: 3
-
apps/server/src/orchestration-v2/CheckpointRestoreSafety.test.tsapps/server/src/orchestration-v2/CheckpointRestoreSafety.tsdocs/user/composer.md
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
External image Recent review info
-
External image Run configuration
-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-31865
- File: .coderabbit.config.ts
- Commit: e4000e2
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
b3431e79-180a-4adb-826b-54b0fba6a23b
External image Commits
-
Reviewing files that changed from the base of the PR and between 2756da402b5d795baa05762cba1706a2c0e2fac8 and e4000e221bf7633bc6eb9258379fd2436ff7894e.
External image Files selected for processing: 3
-
apps/server/src/orchestration-v2/CheckpointRestoreSafety.test.tsapps/server/src/orchestration-v2/CheckpointRestoreSafety.tsdocs/user/composer.md
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
-
Thanks for this. #31874 makes the same change and is the one being kept: Keep #31874 instead: it addresses the same open issue, #31865, and is the more complete fix. Both PRs currently merge without conflicts and have all reported checks passing: 30 for that PR and 33 for this one. The other PR additionally inspects native children's raw pending tools and provider activity, and ancestor-owned background work. Those checks matter because main's background-work derivation omits provider and tool tasks when a child has no app-owned run; this PR relies on that shell summary and can therefore overlook unfinished native-child work. The other PR includes regression cases for those conditions. Main still lacks either ownership exception, and distinctive-line history searches found no implementation of this change.
Closing as a duplicate.