fix: sync project root artifacts into worktree before deriveState to prevent stale DB loop (#853) (#855)

This commit is contained in:
Tom Boucher 2026-03-17 10:19:37 -04:00 committed by GitHub
parent 0abc61987d
commit 16bda686a1

View file

@ -166,6 +166,41 @@ import { hasPendingCaptures, loadPendingCaptures, countPendingCaptures } from ".
// auto-mode reads stale state from the project root and re-dispatches
// already-completed units.
/**
* Sync milestone artifacts from project root INTO worktree before deriveState.
* Covers the case where the LLM wrote artifacts to the main repo filesystem
* (e.g. via absolute paths) but the worktree has stale data. Also deletes
* gsd.db in the worktree so it rebuilds from fresh disk state (#853).
* Non-fatal sync failure should never block dispatch.
*/
function syncProjectRootToWorktree(projectRoot: string, worktreePath: string, milestoneId: string | null): void {
if (!worktreePath || !projectRoot || worktreePath === projectRoot) return;
if (!milestoneId) return;
const prGsd = join(projectRoot, ".gsd");
const wtGsd = join(worktreePath, ".gsd");
// Copy milestone directory from project root to worktree if the project root
// has newer artifacts (e.g. slices that don't exist in the worktree yet)
try {
const srcMilestone = join(prGsd, "milestones", milestoneId);
const dstMilestone = join(wtGsd, "milestones", milestoneId);
if (existsSync(srcMilestone)) {
mkdirSync(dstMilestone, { recursive: true });
cpSync(srcMilestone, dstMilestone, { recursive: true, force: false });
}
} catch { /* non-fatal */ }
// Delete worktree gsd.db so it rebuilds from the freshly synced files.
// Stale DB rows are the root cause of the infinite skip loop (#853).
try {
const wtDb = join(wtGsd, "gsd.db");
if (existsSync(wtDb)) {
unlinkSync(wtDb);
}
} catch { /* non-fatal */ }
}
/**
* Sync dispatch-critical .gsd/ state files from worktree to project root.
* Only runs when inside an auto-worktree (worktreePath differs from projectRoot).
@ -2080,6 +2115,14 @@ async function dispatchNextUnit(
// Non-fatal — health gate failure should never block dispatch
}
// ── Sync project root artifacts into worktree (#853) ─────────────────
// When the LLM writes artifacts to the main repo filesystem instead of
// the worktree, the worktree's gsd.db becomes stale. Sync before
// deriveState to ensure the worktree has the latest artifacts.
if (originalBasePath && basePath !== originalBasePath && currentMilestoneId) {
syncProjectRootToWorktree(originalBasePath, basePath, currentMilestoneId);
}
const stopDeriveTimer = debugTime("derive-state");
let state = await deriveState(basePath);
stopDeriveTimer({