From 26aa97f0ef19ba8e3218182eef8dba02e0e82ca0 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Wed, 13 May 2026 18:56:59 +0200 Subject: [PATCH] fix(work): bump sandcastle maxIterations so agents finish + commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sandcastle's default maxIterations: 1 cut every agent off after its first response, so files written inside the sandbox never made it into a captured commit. The decomposer wrote 9 epic + story files, hit the limit, and sandcastle returned 0 commits — the host saw nothing. decompose.mjs: maxIterations 10 (small authoring task — read context, write files, commit). Override via env SANDCASTLE_DECOMPOSE_ITERATIONS. dispatch.mjs: - Implementer: maxIterations 30 (full TDD slice — read context, red test, green impl, run all five gates, commit). Override via SANDCASTLE_IMPLEMENTER_ITERATIONS. - Reviewer: maxIterations 10 (read diff + task spec, decide). Override via SANDCASTLE_REVIEWER_ITERATIONS. Each call site documents WHY the value was picked + names the env override inline so tuning is discoverable from the code. --- scripts/work/decompose.mjs | 6 ++++++ scripts/work/dispatch.mjs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/scripts/work/decompose.mjs b/scripts/work/decompose.mjs index 5f9b911..bf0d02e 100644 --- a/scripts/work/decompose.mjs +++ b/scripts/work/decompose.mjs @@ -160,6 +160,12 @@ export async function executeDecompose(prdId, prdPath, prdText) { promptFile: decomposerPrompt, promptArgs: { PRD_FILE_CONTENT: prdText }, cwd: REPO_ROOT, + // Sandcastle's default maxIterations: 1 cut the agent off after its + // first response — files were written inside the sandbox but never + // captured as commits. Decompose is a small authoring task (read + // context, write epic + stories, commit); 10 iterations is enough + // room. Tune via env SANDCASTLE_DECOMPOSE_ITERATIONS. + maxIterations: Number(process.env.SANDCASTLE_DECOMPOSE_ITERATIONS ?? 10), }); } catch (e) { console.error("✗ Decomposer dispatch failed:", e.message); diff --git a/scripts/work/dispatch.mjs b/scripts/work/dispatch.mjs index 0c07889..743f938 100644 --- a/scripts/work/dispatch.mjs +++ b/scripts/work/dispatch.mjs @@ -231,6 +231,12 @@ async function executeDispatch() { promptFile: implementerPrompt, promptArgs: { TASK_FILE_CONTENT: taskSpec }, cwd: REPO_ROOT, + // Implementer runs a full TDD slice (read context, red test, green + // impl, run all five gates, commit). 30 iterations matches typical + // slice shape. Tune via env SANDCASTLE_IMPLEMENTER_ITERATIONS. + maxIterations: Number( + process.env.SANDCASTLE_IMPLEMENTER_ITERATIONS ?? 30, + ), }); } catch (e) { console.error("✗ Implementer dispatch failed:", e.message); @@ -280,6 +286,10 @@ async function executeDispatch() { promptFile: reviewerPrompt, promptArgs: { TASK_FILE_CONTENT: taskSpec, DIFF: diff }, cwd: REPO_ROOT, + // Reviewer reads the diff + task spec and decides (approve/reject). + // Smaller surface than the implementer; 10 iterations is plenty. + // Tune via env SANDCASTLE_REVIEWER_ITERATIONS. + maxIterations: Number(process.env.SANDCASTLE_REVIEWER_ITERATIONS ?? 10), }); console.log(`Reviewer returned. stdout follows:\n${reviewResult.stdout}`);