fix(issue-21): reviews 8f141362 N1 and 275fdc4f R4/R5 - clean refusal for a broken worktree, no init over existing files, check retained submodule repositories

- N1 (planner-reviewer-claude-01) worktree_remove.sh: when `git status` fails
  in the worktree (e.g. its directory was deleted), judge_tree returned before
  METHOD was set and the summary line died under set -u with exit 1. METHOD
  now has its default before the function; the refusal is exit 3 with
  "nothing was changed", plus a `git worktree prune` hint when the directory
  is gone. Same for --dry-run.
- R4 (planner-reviewer-codex-01) worktree_prepare.sh: a submodule path that is
  not initialised yet but already holds files made the clone fail, and the
  rollback's `deinit -f` then deleted those files. --submodules now refuses
  such a path up front (new exit 3, nothing changed), which also makes the
  rollback's premise true: after a failed attempt, everything under a
  not-yet-initialised path was created by that attempt.
- R5 (planner-reviewer-codex-01) lib_py/worktree.py: `submodule foreach`
  visits initialised checkouts only, but a deinit'd submodule keeps its
  repository - stash and unpushed commits included - under the worktree's
  modules/, which the forced removal deletes. Every repository under modules/
  (nested ones included) is now checked directly (`--git-dir`): commits on no
  remote (HEAD included) and refs/stash with its reflog. A directory that looks
  like a partial repository cannot be checked and refuses.
- Also: the rollback loops are C-style (`seq 0 -1` counts down on BSD), and
  prepare warns that --base is ignored for an existing branch.

Tests W6i (deleted worktree directory, with and without --dry-run), W6j and
W6j2 (stash / unpushed commit in a deinit'd submodule's repository) and W6k
(existing files in an uninitialised submodule path). Skill docs and the design
doc describe the new refusal and the wider repository check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017R3Eg7MEpSWnm1oB9ZPP6G
This commit is contained in:
GodopuandClaude Opus 5 committed 2026-09-14 18:14:13 +00:00
1 parent bbbbb95ef6
commit c7c559b7aa
7 files changed
+168 -8

No files matched your search

@@ -247,7 +247,8 @@ bash .agents/skills/multi-agent-mux-create/scripts/worktree_prepare.sh \
- **Submodules are opt-in** (`--submodules`). Initialisation writes `submodule.<name>.url` to the shared `.git/config`, and any attempt - even a failed one - leaves a `modules/` directory that makes a plain `git worktree remove` refuse. A failed `--submodules` undoes only what that attempt created - new submodule checkouts are deinitialised before their git dirs are deleted, so the worktree stays a usable checkout; submodules initialised earlier and pre-existing `submodule.*` values are kept - and exits 1; re-run without `--submodules` to finish.
- `--creator-agent` creates the creator through this skill with the control root's binding and `MAM_NO_SUBSCRIBER_DAEMON=1`; the row's `pane.cwd` is the worktree.
- Prints `BASE=<sha>`: record it **before** delegating the implementation, then review with `run_loop.sh --worktree <WT> --base "$BASE" --review-only`.
- Exit codes: 0 ok, 1 git / submodule / create failure, 2 usage or path rule.
- A submodule path that is not initialised yet but already holds files refuses `--submodules` up front (exit 3, nothing changed): the clone would fail on it and a rollback could not tell those files from its own.
- Exit codes: 0 ok, 1 git / submodule / create failure, 2 usage or path rule, 3 refused to protect existing content (nothing changed).
- create itself: a control-plane binding that cannot be computed is refused (exit 2) for a `--workspace` other than the control root and warned about for the control root; the immediate reconcile and the watchdog run the control root's code.
## Pitfalls