fix: make worktree lifecycle failures durable - #2719
Conversation
|
| Filename | Overview |
|---|---|
| packages/server/src/server/worktree/commands.ts | Archive commands now reject unresolved workspace targets instead of returning fabricated success and propagate cleanup state. |
| packages/server/src/server/workspace-archive-service.ts | Centralizes full lifecycle archive behavior and preserves logical or physical cleanup failures for callers. |
| packages/server/src/server/workspace-cleanup-retry-service.ts | Adds bounded autonomous cleanup retries fenced to the exact archived worktree incarnation. |
| packages/server/src/server/workspace-lifecycle-coordinator.ts | Coordinates ownership mutations, archive reservations, and filesystem-identity exclusion. |
| packages/server/src/server/agent/create-agent/create.ts | Holds lifecycle ownership reservations through active-workspace validation and agent attachment. |
| packages/server/src/server/session/workspace-provisioning/workspace-provisioning-service.ts | Coordinates directory workspace creation with cleanup exclusion and post-wait directory revalidation. |
| packages/server/src/server/bootstrap.ts | Wires lifecycle services into daemon startup and awaits active cleanup work during shutdown. |
| packages/protocol/src/messages.ts | Extends archive responses with optional removed-directory and cleanup-pending status fields. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
C[Workspace or agent creation] --> R[Reserve lifecycle ownership mutation]
R --> V[Validate active workspace]
V --> A[Attach agent or terminal ownership]
A --> U[Release reservation]
X[Archive request] --> Q[Claim workspace archive]
Q --> D[Drain reserved ownership mutations]
D --> L[Archive logical workspace state]
L --> P[Attempt physical cleanup]
P -->|Success| S[Report cleanup complete]
P -->|Failure| F[Persist fenced cleanup obligations]
F --> B[Bounded retry with capped backoff]
B --> P
Reviews (5): Last reviewed commit: "fix(server): drain create lifecycle reco..." | Re-trigger Greptile
|
A fresh human exact-tip review found four lifecycle gaps that the current tests and Greptile pass did not cover: non-MCP terminal/project-removal paths can bypass the archive reservation; merge auto-archive does not persist cleanup retry intent; explicit unknown workspace IDs still return success; and a partial multi-workspace retry can omit an archived sibling teardown obligation. I have returned this PR to draft while I add the exact regressions and repair those paths. The branch and existing evidence remain unchanged until the focused follow-up is verified. |
|
The four exact-tip lifecycle gaps reported in the prior draft comment are now repaired at d5743f9, with the proof receipt at submitted head d3530db. Added regressions cover post-archive agent/MCP/desktop terminal attachment, project-removal fencing, durable merge-autoarchive cleanup state, explicit unknown workspace IDs, and partial sibling cleanup retries. Node 24 proof: 317 passed / 4 skipped, final ownership subset 144/144, server build/typecheck and changed-file lint/format all pass. Returning the PR for exact-head review. |
|
The four human-review P1 classes have been repaired at exact head d3530db with focused and package proof. Returning the PR to draft for one independent exact-tip review of the repaired state; implementer proof alone is not the acceptance boundary. |
|
Follow-up exact-tip review also caught auto-archive false success when a resolver returns an inactive clean workspace or cleanup remains pending. That is now repaired at 4864613 with 16/16 truthfulness tests; submitted head is bd90c39. A separate final-refresh ownership closure race was then identified, so I am keeping this PR in draft while I add that deterministic gate and repair. |
|
The final-refresh ownership closure and pending-cleanup automation seams are now repaired. Archive discovery iterates to a stable target set and waits existing setup/ownership work for every newly discovered sibling (2ee2896); registry I/O failures remain truthful, and created-worktree, schedule, project, hub, and normal workspace automation reject cleanupPending as retryable failure (7e9b8bf). Exact submitted head: 4a54864. Final proof: 182 passed / 4 skipped, closure 26/26, auto-archive 16/16, combined closure/auto 42/42, Node24 server build/typecheck, lint/format/diff green. PR remains draft for another exact-tip review. |
|
Exact-tip follow-up for the final cleanup-retry review: pushed head The repair adds an autonomous daemon cleanup owner that discovers persisted New regression proof includes two archived sibling workspaces with distinct teardown directories on one worktree; both teardown obligations run before the single deletion. The 10-file lifecycle/schedule suite passed 387 tests with 4 platform-specific skips; server build/typecheck and changed-file lint/format/diff pass on Node 24. |
|
Second exact-tip retry follow-up: pushed head Cleanup retry no longer runs on the daemon readiness path: Regressions prove a never-resolving cleanup does not block start or stop, and with |
|
Review follow-up is now pushed at exact head |
|
Final P1 follow-up is pushed at exact head |
|
Filesystem-identity follow-up is pushed at exact head |
|
Receipt reproducibility follow-up is pushed at exact head |
|
Terminal independent exact-tip review is clean at |
|
Exact-tip lifecycle follow-up is pushed at This repair gives every WebSocket Session the one daemon-owned create-agent lifecycle dispatcher while retaining Session-local worktree creation behavior; reports failed cleanup cancellation as unresolved for durable restart recovery; rearms cleanup only for the workspace IDs named by Focused proof: lifecycle dispatch 11/11; Session 153/153; related Session suites 136 passed / 4 platform skips; WebSocket suites 39/39; bootstrap shutdown 19/19; cleanup restart service 3/3. The create-worktree auto-archive E2E run passed 10 cases while one case hit its 5-second limit under concurrent load; that exact case then passed in isolation (1 passed / 10 skipped). Repository |
Linked issue
Closes #2720
Type of change
What does this PR do
Worktree setup, ownership attachment, archive, physical cleanup, and replacement workspace creation currently cross several independent asynchronous paths. Late ownership or workspace creation can race archive, and a failed cleanup can be reported as success or lose the identity needed for a safe retry.
This focused daemon/protocol change gives those operations one lifecycle boundary:
It contains no provider-health behavior, fleet topology, Plexer policy, machine paths, release bump, or unrelated local patches.
How did you verify it
The lifecycle-only candidate was rebuilt directly from official stable
v0.2.5(6fc491e6220fba6543bbbe4bf1b1f58cfe59228b), then merged normally with upstreammainat70ed70d36e2eabd3876a22931954319ec202c902. Review repairs were added normally on top; no force push or history rewrite was used.Exact submitted head:
bb956ee4c7640c39d14a7984c1695650fa57a8bb(tree2e019cb70c5e68d986f2ab29d99cc5c90508b748).Exact focused lifecycle-dispatch amendment:
bb956ee4c7640c39d14a7984c1695650fa57a8bb, reconstructed only from frozen sources67e23daf21868648ec2a696c38a142b4af053bb6and5de7e1d0b246b688cc568041c66d56da46c86318. No fork receipt or manifest file was changed.Exact cleanup-only/cancellation source repair:
5e17fcf769cb855326683413cdcd9b3cbe82ba43(treee83f37f06eeb44d5b87ff30d5ca18c0d25288f5b).Exact cleanup/create exclusion source repair:
5c70d522437ea0c02c1e769ee5f9975b8077811e(tree1b4b0a140a483504225e043bfdd5cf1f26e7f875).Exact filesystem-identity lock repair:
759ed14f0b24499f0a3f161cf64c920ac3393c4b(tree602929fb3aa5106fecf438ab0b4d3570d7daa62b).npx vitest run packages/server/src/server/agent/create-agent-lifecycle-dispatch.test.ts packages/server/src/server/bootstrap.smoke.test.ts --bail=1passed 26 tests in 2 files.The stable verification commits and receipts remain in
patches/so the seam is auditable and can be dropped when an equivalent upstream release lands.This contribution was developed with AI assistance; every verification claim above comes from an actual run against the submitted branch.
Checklist
npm run typecheckpassesnpm run lintpasses for every changed file