Auto-mode stuck loop: complete-slice re-dispatches with no attempt cap when LLM silently refuses to write SUMMARY
Problem
Auto-mode gets stuck in summarizing → complete-slice when the dispatched LLM finishes the unit cleanly (0 errors, ~13 tool calls) but silently refuses to write the slice SUMMARY.md/UAT.md — typically reasoning "Slice needs execution follow-up." — without calling gsd_slice_complete, gsd_task_reopen, or gsd_slice_replan. The state machine has no exit: verify-fail fires, the same rule re-dispatches, and the loop only ends via the generic stuck-loop detector + auto-exit.
Observed on M031/S02: three re-dispatches of complete-slice/M031/S02 in a row (seq 601–602 + retries), each producing zero SUMMARY on disk while all five task SUMMARYs are present and DB has all tasks complete.
Root Cause
auto-dispatch.ts — the summarizing → complete-slice rule unconditionally re-dispatches whenever state.phase === "summarizing". No attempt counter, no divergence signal, no fallback like run-uat's MAX_UAT_ATTEMPTS.
// auto-dispatch.ts (summarizing → complete-slice rule)
{
name: "summarizing → complete-slice",
match: async ({ state, mid, midTitle, basePath }) => {
if (state.phase !== "summarizing") return null;
if (!state.activeSlice) return missingSliceStop(mid, state.phase);
const sid = state.activeSlice.id;
// No attempt counter, no divergence check.
return {
action: "dispatch",
unitType: "complete-slice",
unitId: `${mid}/${sid}`,
prompt: await buildCompleteSlicePrompt(mid, midTitle, sid, sTitle, basePath),
};
},
},auto-recovery.ts (verifyUnitCompletion) only checks DB slice.status === "complete" and disk SUMMARY/UAT. It has no way to distinguish "unit crashed" from "unit finished cleanly but LLM chose not to act" — both look like existsSync false, so the dispatcher happily goes around again.
Expected Behavior
Two-part fix:
- Cap
complete-slicere-dispatch attempts analogous torun-uat'sMAX_UAT_ATTEMPTS. After N (suggested: 2) attempts where the previous unit ended witherrors === 0,toolCalls > 0, and no SUMMARY on disk and no reopen/replan call, escalate: writeS##-BLOCKER.mdcontaining the LLM's last reasoning, transition to blocked, and stop the loop for human/planner review. - Divergence signal in
buildCompleteSlicePrompt: whenmetrics.jsonalready has a priorcomplete-slice/<mid>/<sid>entry withcost > 0,errors === 0, and SUMMARY still absent, inject a mandatory-action block into the prompt that forces exactly one ofgsd_slice_complete,gsd_task_reopen,gsd_slice_replan, orwrite S##-BLOCKER.md. Silent refusal must not be a valid outcome.
Environment
- GSD version: 3.0.0
- Model: claude-opus-4-7
- Unit:
complete-slice/M031/S02
Reproduction Context
- Phase: summarizing (all 5 tasks in slice have
status=completein DB andT0N-SUMMARY.mdon disk) - Trigger: LLM dispatched for
complete-slicecompletes 13 tool calls with 0 errors, reasons "Slice S02 needs execution follow-up.", never writesS02-SUMMARY.mdorS02-UAT.md, never callsgsd_task_reopen - Result:
verifyUnitCompletionreportsexistsSync falseforS02-SUMMARY.md; dispatcher matchessummarizing → complete-sliceagain; same LLM behavior; loop until stuck-loop detector
Forensic Evidence
- 3 dispatches of
complete-slice/M031/S02within 20 attempts - Verify-fail warnings:
existsSync falsefor.../S02/S02-SUMMARY.md(x3) and.../S02/tasks/T05-SUMMARY.md(x2 — resolved in prior attempt) - Metrics: successful attempt cost $1.30 / 1m33s / 13 tool calls / 0 errors — no SUMMARY produced
- Recent journal (2026-07-11T10:53–10:56Z): three
dispatch-match rule=summarizing → complete-slice unit=M031/S02events, each followed within 3s byauto-exit - Related but distinct: prior issue on complete-slice reopening tasks for inherited verification failure — this new symptom is complete-slice refusing to write SUMMARY entirely, so the state machine has no exit at all
Auto-generated by /gsd forensics
Source: gsd-build/gsd-2