From 35f63f050a3e1ade10a64568ce4fd7f6e2479936 Mon Sep 17 00:00:00 2001 From: deseltrus Date: Mon, 16 Mar 2026 20:13:16 +0100 Subject: [PATCH] fix: derive initial state from worktree when one exists (#654) When auto-mode restarts after being stopped, the initial deriveState() reads from the project root which has stale .gsd/ metadata. Completed units appear incomplete, causing re-dispatch of finished work. The auto-worktree (if it exists from the previous run) has the current state. After the initial deriveState(base), check if an auto-worktree exists for the active milestone and re-derive from there. This is safe because: - Only triggers when worktree isolation is enabled - Only when not already inside a worktree - Only when an auto-worktree actually exists for the milestone - The worktree setup at lines 976+ still runs normally after Fixes #654 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/resources/extensions/gsd/auto.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/resources/extensions/gsd/auto.ts b/src/resources/extensions/gsd/auto.ts index b9058d6e6..2574272f8 100644 --- a/src/resources/extensions/gsd/auto.ts +++ b/src/resources/extensions/gsd/auto.ts @@ -824,6 +824,23 @@ export async function startAuto( let state = await deriveState(base); + // ── Stale worktree state recovery (#654) ───────────────────────────────── + // When auto-mode was previously stopped and restarted, the project root's + // .gsd/ directory may have stale metadata (completed units showing as + // incomplete). If an auto-worktree exists for the active milestone, it has + // the current state — re-derive from there to avoid re-dispatching + // finished work. + if ( + state.activeMilestone && + shouldUseWorktreeIsolation() && + !detectWorktreeName(base) + ) { + const wtPath = getAutoWorktreePath(base, state.activeMilestone.id); + if (wtPath) { + state = await deriveState(wtPath); + } + } + // ── Milestone branch recovery (#601) ───────────────────────────────────── // When auto-mode was previously stopped, the milestone branch is preserved // but the worktree is removed. The project root (integration branch) may