fix(auto-resume): creation-failed swallowed in resume path — emits confusing 'Unhandled phase' guard-block when project root is on milestone branch
Problem
When a prior auto-mode session exits without merging (project root stays checked out on milestone/<MID>), the next /gsd auto invocation fails silently in the resume path and then emits a confusing non-actionable guard-block: "Unhandled phase 'executing' — run /gsd doctor to diagnose." instead of surfacing the real cause.
Root Cause
Two bugs compound:
Bug 1 — auto-start.js resume path silently ignores creation-failed
In the resume path (s.paused = true), enterMilestone failure handling only stops auto-mode for lease-conflict. All other failures (including creation-failed) are silently swallowed and execution continues with dispatchBasePath = project root:
// auto-start.js ~line 2035 (resume path)
if (!enterResult.ok && enterResult.reason === "lease-conflict") {
ctx.ui.notify(`Cannot resume milestone...`);
await stopAuto(ctx, pi, "lease-conflict during resume");
return;
}
// ALL OTHER FAILURES fall through — rebuildScope still runs, orchestrator starts
rebuildScope(s.basePath, s.currentMilestoneId);Compare the fresh-start path (auto-start.js ~line 932) which handles all non-ok reasons and calls releaseLockAndReturn().
Bug 2 — worktree-lifecycle.js error message mentions "another worktree" but the real conflict is the project root's main worktree
When milestone/M001 is checked out in the project root, git reports:
Branch "milestone/M001" is already in use by another worktree.
The "another worktree" is the main working tree itself — not a registered .gsd/worktrees/ entry. The error is accurate but lacks an actionable recovery hint. The user needs git checkout main (or their integration branch), not /worktree remove M001.
Expected Behavior
The resume path should mirror the fresh-start path's exhaustive error handling. When enterResult.reason === "creation-failed" and the error message contains "already in use", the engine should:
- Detect whether the project root's current branch matches
milestone/<MID> - Stop auto-mode with a clear message:
"Project root is checked out on milestone/M001. Run git checkout main to recover, then re-run /gsd auto."
Minimal fix — in auto-start.js resume path, add parity with fresh-start path:
if (!enterResult.ok) {
const isBranchInUse = enterResult.reason === "creation-failed"
&& String(enterResult.cause?.message ?? "").includes("already in use");
if (isBranchInUse) {
ctx.ui.notify(
`Cannot resume: project root is checked out on milestone/${s.currentMilestoneId}. ` +
`Run "git checkout main" then re-run /gsd auto.`,
"error"
);
} else if (enterResult.reason === "lease-conflict") {
ctx.ui.notify(`Cannot resume milestone ${s.currentMilestoneId}: lease held by another worker.`, "error");
} else {
ctx.ui.notify(`Cannot resume: worktree entry failed (${enterResult.reason}).`, "error");
}
await stopAuto(ctx, pi, `resume-worktree-failed: ${enterResult.reason}`);
return;
}Environment
- GSD version: 3.0.0
- Isolation mode: worktree
- Active milestone: M001 / active slice: S05
- Project root branch at failure:
milestone/M001(31 commits ahead of main, unmerged)
Reproduction Context
- Auto-mode runs tasks on
milestone/M001branch inside.gsd/worktrees/M001/ - Session exits without merge (e.g. OS sleep, SIGKILL, manual stop)
- Worktree directory is cleaned up but the project root remains on
milestone/M001 - User runs
/gsd auto— bootstrap enters resume path enterMilestonefails:Branch "milestone/M001" is already in use by another worktree- Resume path swallows the error, orchestrator starts, dispatch fires
resolveDispatch - Guard-block emitted:
"Unhandled phase 'executing' — run /gsd doctor to diagnose." - Auto-mode stalls; user cannot restart without knowing to run
git checkout main
Forensic Evidence
2026-06-09T08:22:23Z [worktree-create-failed] flow=d9232403
error: "Branch \"milestone/M001\" is already in use by another worktree."
fallback: "project-root"
2026-06-09T08:22:25Z [guard-block] flow=auto-orc
reason: "Unhandled phase \"executing\" — run /gsd doctor to diagnose."
2026-06-09T08:23:23Z [worktree-orphaned] flow=73a43fce
milestoneId: "M001", reason: "in-progress-unmerged"
commitsAhead: 31, worktreeDirExists: falseAnomalies from forensics: 8 unmerged worktree exits, 1 worktree create failure, 2 guard-block events.
Auto-generated by /gsd forensics
Source: gsd-build/gsd-2