worktree adoption can take over and then delete a hand-made worktree #69

Closed
opened 2026-08-24 00:41:38 +01:00 by naps62-yolo · 1 comment
Collaborator

crates/maestro-daemon/src/worktree.rs — spawn can adopt, and later delete, a worktree the operator created by hand.

run_add finds the target path occupied, asks registered_for() whether a worktree for that branch lives there, and adopts it. That check cannot tell a tree this daemon leaked from one the operator made themselves.

Default placement is <repo>/worktrees/<branch> — exactly the convention this repository already uses. /home/naps62/tea/maestro/worktrees/plan is a real, hand-made worktree. Spawning a session on branch plan in this repo would silently take it over, and because cleanup is unconditional, killing that session runs git worktree remove on it.

The dirty-work guard does not save it either: it runs git status --porcelain --ignored=no, so a tree whose only uncommitted content is ignored — target/, .env, node_modules — reads as clean and is removed without complaint.

Introduced by the adoption fix for the guarded-leftover dead end. The fix must distinguish trees the daemon created: record them (a marker file under the worktree's admin dir, or the session sidecar) and adopt only those.

Do not run blitz/spawn-v2 against a repository holding worktrees you care about until this is fixed.

`crates/maestro-daemon/src/worktree.rs` — **spawn can adopt, and later delete, a worktree the operator created by hand.** `run_add` finds the target path occupied, asks `registered_for()` whether a worktree for that branch lives there, and adopts it. That check cannot tell a tree this daemon leaked from one the operator made themselves. Default placement is `<repo>/worktrees/<branch>` — exactly the convention this repository already uses. `/home/naps62/tea/maestro/worktrees/plan` is a real, hand-made worktree. Spawning a session on branch `plan` in this repo would silently take it over, and because cleanup is unconditional, killing that session runs `git worktree remove` on it. The dirty-work guard does not save it either: it runs `git status --porcelain --ignored=no`, so a tree whose only uncommitted content is ignored — `target/`, `.env`, `node_modules` — reads as clean and is removed without complaint. Introduced by the adoption fix for the guarded-leftover dead end. The fix must distinguish trees the daemon created: record them (a marker file under the worktree's admin dir, or the session sidecar) and adopt only those. **Do not run `blitz/spawn-v2` against a repository holding worktrees you care about until this is fixed.**
naps62-yolo added this to the Spawn v2 milestone 2026-08-24 00:41:38 +01:00
naps62-yolo added the area/daemontype/fixdifficulty/hard labels 2026-08-24 00:41:38 +01:00
Author
Collaborator

Superseded by the Worktree lifecycle milestone, specifically #77.

This dissolves rather than gets fixed: once nothing is ever adopted and a path collision is sidestepped with a numeric suffix, there is no adoption path that could take over a hand-made worktree, and no single directory for two concurrent creates to contend over.

Superseded by the **Worktree lifecycle** milestone, specifically #77. This dissolves rather than gets fixed: once nothing is ever adopted and a path collision is sidestepped with a numeric suffix, there is no adoption path that could take over a hand-made worktree, and no single directory for two concurrent creates to contend over.
This repo is archived. You cannot comment on issues.
1 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: naps62/maestro#69