diff --git a/tools/web/run-wbv2-scheduler.mjs b/tools/web/run-wbv2-scheduler.mjs index 9f950fbcc..61374033b 100644 --- a/tools/web/run-wbv2-scheduler.mjs +++ b/tools/web/run-wbv2-scheduler.mjs @@ -219,6 +219,15 @@ function sourceMappingReadiness(pointer) { const card = read(cardPath); const implementation = card.match(/- Implementation entrypoint: `([^`]+)`/u)?.[1]; if (!implementation) return { ok: false, reason: "implementation_entrypoint_missing", taskClass }; + if (/targetImplementationClass:\s*LOCAL_EXACT/u.test(card)) { + const batchId = card.match(/^- batchId:\s*`?([^`\n]+)`?/mu)?.[1]; + const selected = card.match(/^- selectedRecordIds:\s*(\[[^\n]+\])/mu)?.[1]; + if (!batchId || !selected) return { ok: false, reason: "batch_contract_missing", taskClass }; + try { + const selectedRecordIds = JSON.parse(selected); + if (!Array.isArray(selectedRecordIds) || selectedRecordIds.length === 0) return { ok: false, reason: "batch_selection_missing", taskClass }; + } catch { return { ok: false, reason: "batch_selection_invalid", taskClass }; } + } // Continuation source tasks must have an explicit, non-generic phase mapping. // This prevents a long-running loop from replaying an older marker forever. diff --git a/tools/web/run-wbv2-supervisor.mjs b/tools/web/run-wbv2-supervisor.mjs index 84eff0b15..ce2428b99 100644 --- a/tools/web/run-wbv2-supervisor.mjs +++ b/tools/web/run-wbv2-supervisor.mjs @@ -81,10 +81,12 @@ const stopOnFatal = (error, source) => { if (fatalHandled) return; fatalHandled = true; try { + failureLedger.record({ task: currentTask()?.task ?? "UNKNOWN", phase: "supervisor", reason: source, detail: error?.message ?? String(error) }); writeCheckpoint({ state: "blocked", iteration, reason: source, error: error?.message ?? String(error) }); appendLog(`blocked reason=${source} error=${error?.message ?? String(error)}`); } finally { + failureLedger.flush(); releaseLock(); process.exit(1); }