Repository navigation
fix(server): remove checkpoint refs when deleting threads - #25182
juliusmarminge wants to merge 6 commits into
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thread deletion now enqueues a replay-safe checkpoint.cleanup outbox effect carrying the thread's checkpoint cwds and scope IDs. ResourceCleanupService deletes every ref under the thread's V1 turn namespace and each V2 scope namespace in one git update-ref transaction, so a locked ref fails the effect and the worker retries it instead of silently skipping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lock contention outlasting the worker's attempt budget terminalized the cleanup, and detection errors were read as "not a repository", so the effect reported success without deleting refs. Cleanup now retries on the existing capped backoff and skips only directories that no longer exist or are not Git repositories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r cleanup Ref listing ran through VcsProcess's 1 MB output cap, which truncates silently, so a namespace with ~20k refs was acknowledged with thousands left. Enumerate and delete in bounded --count batches until none remain, failing (not truncating) if one listing ever overflows. Checkpoint cleanup retries until it succeeds and the outbox orders effects per thread, so it now queues after scheduled-task, terminal, preview, and attachment cleanup instead of blocking them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Repository detection reported a repository with a malformed config as not a repository, so cleanup succeeded and left the deleted thread's refs behind. The namespace sweep now skips a cwd only when Git itself says it is not a repository (or Git is absent); any other failure keeps the outbox effect retryable. Deletes also pass --no-deref so a symbolic ref in a deleted namespace never removes another thread's ref. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR requires human approval — Thread and project deletion now enqueue destructive Git checkpoint-ref cleanup across multiple workspaces, with transactional deletion and retry-until-success behavior; rollback error handling also changes. The intent is a focused cleanup fix with strong tests, but its cross-cutting production impact is broader than a small self-contained change. You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 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.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Reference namespace deletion apps/server/src/checkpointing/*, apps/server/src/orchestration-v2/CheckpointService.ts, apps/server/src/orchestration-v2/CheckpointRollbackService.ts, apps/server/src/vcs/* |
Thread and scope namespace helpers provide reference prefixes. The checkpoint store and Git driver support namespace deletion, with validation and batched ref removal. Rollback logs stale-ref deletion failures. Tests cover large namespaces and symbolic refs. |
Thread deletion cleanup scheduling apps/server/src/orchestration-v2/EffectOutbox.ts, apps/server/src/orchestration-v2/ThreadDeletion.ts, apps/server/src/orchestration-v2/Orchestrator.ts, apps/server/src/project/ProjectService.ts, apps/server/src/orchestration-v2/ThreadDeletion.test.ts, apps/server/src/project/ProjectService.deletion.test.ts |
The deletion planner gathers thread worktree, project workspace, and checkpoint-scope paths and adds a cleanup effect. Deletion callers provide project workspace and scope data. The outbox accepts and requeues the effect after process loss. |
Checkpoint cleanup execution and retries apps/server/src/orchestration-v2/ResourceCleanupService.ts, apps/server/src/orchestration-v2/EffectWorker.ts, apps/server/src/orchestration-v2/runtimeLayer.test.ts, apps/server/src/guest/GuestShareService.test.ts |
The cleanup service deletes thread and scope namespaces in existing working directories. The worker retries cleanup effects until success. Tests cover lock retries, process-loss recovery, missing directories, and Git errors. |
Priority:
Estimated code review effort: 4 (Complex) | ~40 minutes
Change: Bug fix
Sequence Diagram(s)
sequenceDiagram
participant ThreadDeletion
participant EffectOutbox
participant EffectWorker
participant ResourceCleanupService
participant CheckpointStore
ThreadDeletion->>EffectOutbox: enqueue checkpoint.cleanup
EffectOutbox->>EffectWorker: provide cleanup effect
EffectWorker->>ResourceCleanupService: pass thread, workspaces, and scope IDs
ResourceCleanupService->>CheckpointStore: delete namespaces in existing directories
Possibly related issues
- Issue 24083 reports unpruned checkpoint refs from deleted threads. This change schedules deletion of thread and scope refs, including legacy turn refs.
Suggested labels: bugfix, size:L
Suggested reviewers: maria-rcks, t3dotgg, yash-singh1
Merge Risk: 
Minimal · up to de68d
-
No concrete issue remains that should block merging after normal checks.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description covers the problem, implementation, scope references, verification results, known limitations, and agent attribution. It provides detailed evidence and test results that align with the required template.
-
Finishing Touches: 💡 2
-
⚔️ Resolve merge conflicts: 💡
-
- Resolve merge conflict in branch
takeover/pr-24949
- Resolve merge conflict in branch
🛠️ Fix failing CI checks: 💡
-
- Commit to this branch
- Create a new PR
📝 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.
Deleting a thread left its Git checkpoint refs behind, which cluttered Git tools and kept old snapshot data reachable. Deletion now queues cleanup after checkpoint writes, removes only that thread's old and current refs, and handles removed worktrees through the project repo. Archived threads keep their restore history.
Addresses discussion #13263.
Related bug report: #24083.
Verified with failing regression tests before the fix, real Git tests for packed refs, shared worktrees and lock failures, a capture-order test, and
vp run check:changed.Refs from threads deleted before this change need manual cleanup. Git's normal maintenance reclaims the unused data.
Built with GPT-6.1 Sol high/priority in the Codex harness, with Astra high design and review.
Takeover
Replaces #24949, with thanks to @Bil0000 for identifying the leak and establishing its reproduction and cleanup scope.
Rebuilt the deletion plan around a durable cleanup payload; Git stays in the VCS layer. Cleanup runs last, retries with capped backoff, deletes bounded batches, and never follows symbolic refs.
The original description above is preserved; its verification statements describe the contributor's work. The verification below applies to this replacement.
Evidence
Before/after matrix · Running-server transcript · Independent proof audit: PASS
Fresh isolated servers at before
9296c20e82cef89371e2a4fb433f31c314384261and afterde68dbb1e55355950669fbb33a67aa0f6e2a8c8e. Three threads each completed two ACP fixture-provider turns with real server checkpoint capture: nine refs before deletion. Before retained all three deleted-thread refs; after removed those three and preserved all six archived/retained refs and object IDs. A real ref lock failed cleanup; retry persisted across server restart and succeeded after unlock. Fixture turns made no file edits; this proof covers ref ownership/removal and recovery, not diff fidelity or commercial-model inference.Verification log
GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 vp run check:changed: passed format, lint, both knip passes, GraphQL generation, affected typechecks (two packages), tests (12 files). Process-local Git configuration isolation avoids this machine's remote URL rewrite; no global configuration changed.Implementation and tests: Claude Opus 5.5 in the Claude Agent harness. PR lead, independent review and proof: GPT-6.1 Sol in the Codex harness.