fix: missing STATE.md in fresh worktree deadlocks pre-dispatch health gate (#889) (#895)

This commit is contained in:
Tom Boucher 2026-03-17 13:09:25 -04:00 committed by GitHub
parent 2dd8f481a3
commit 25292f8840
2 changed files with 23 additions and 4 deletions

View file

@ -173,14 +173,19 @@ export async function preDispatchHealthGate(basePath: string): Promise<PreDispat
}
// ── STATE.md existence check ──
// If STATE.md is missing, rebuild it now so the next unit has accurate
// context. Non-blocking — if the rebuild throws, dispatch continues anyway.
// If STATE.md is missing, attempt to rebuild it for the next unit's context.
// Non-blocking — fresh worktrees won't have it until the first unit completes (#889).
try {
const stateFile = resolveGsdRootFile(basePath, "STATE");
const milestonesDir = join(gsdRoot(basePath), "milestones");
if (existsSync(milestonesDir) && !existsSync(stateFile)) {
await rebuildState(basePath);
fixesApplied.push("rebuilt missing STATE.md before dispatch");
try {
await rebuildState(basePath);
fixesApplied.push("rebuilt missing STATE.md before dispatch");
} catch {
// Rebuild failed — non-blocking, dispatch continues
fixesApplied.push("STATE.md missing — will rebuild after first unit completes");
}
}
} catch {
// Non-fatal — dispatch continues without STATE.md if rebuild fails

View file

@ -193,6 +193,20 @@ async function main(): Promise<void> {
assertEq(result.issues.length, 0, "no issues on clean state");
}
console.log("\n=== health gate: missing STATE.md does NOT block dispatch (#889) ===");
{
const dir = realpathSync(mkdtempSync(join(tmpdir(), "doc-proactive-")));
cleanups.push(dir);
// Create milestones dir but no STATE.md — mimics fresh worktree
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
writeFileSync(join(dir, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap\n");
const result = await preDispatchHealthGate(dir);
assertTrue(result.proceed, "gate must NOT block when STATE.md is missing (deadlock #889)");
assertEq(result.issues.length, 0, "missing STATE.md is not a blocking issue");
assertTrue(result.fixesApplied.some((f: string) => f.includes("STATE.md")), "reports STATE.md status as info");
}
console.log("\n=== health gate: stale crash lock auto-cleared ===");
{
const dir = realpathSync(mkdtempSync(join(tmpdir(), "doc-proactive-")));