From 642323a489573f181b7354080ce7d51d1a9d2973 Mon Sep 17 00:00:00 2001 From: Jeremy McSpadden Date: Tue, 17 Mar 2026 18:20:29 -0500 Subject: [PATCH] fix(auto): dispatch retry after verification gate failure (#998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the verification gate fails with retries remaining, handleAgentEnd sets pendingVerificationRetry and deletes the completion key, but then returns early without calling dispatchNextUnit. This leaves auto-mode active but permanently stalled — no new unit is ever dispatched because the dispatch chain is broken. Fix: call dispatchNextUnit immediately after setting up the retry state, with a fallback to the dispatch gap watchdog if dispatch throws. --- src/resources/extensions/gsd/auto.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/resources/extensions/gsd/auto.ts b/src/resources/extensions/gsd/auto.ts index 0904a4d3e..46866b957 100644 --- a/src/resources/extensions/gsd/auto.ts +++ b/src/resources/extensions/gsd/auto.ts @@ -1526,6 +1526,15 @@ export async function handleAgentEnd( // Remove completion key so dispatchNextUnit re-dispatches this unit s.completedKeySet.delete(completionKey); removePersistedKey(s.basePath, completionKey); + // Dispatch retry immediately — without this, handleAgentEnd returns + // without calling dispatchNextUnit, leaving auto-mode stalled (#978). + try { + await dispatchNextUnit(ctx, pi); + } catch (retryDispatchErr) { + const msg = retryDispatchErr instanceof Error ? retryDispatchErr.message : String(retryDispatchErr); + ctx.ui.notify(`Verification retry dispatch error: ${msg}`, "error"); + startDispatchGapWatchdog(ctx, pi); + } return; // ← Critical: exit before DB dual-write and post-unit hooks } else { // Gate failed, retries exhausted (or auto-fix disabled) — pause for human review