fix(work): emit completion signal to stop sandcastle agent loops

Sandcastle re-invokes agents up to maxIterations even when the work is
already done — the decomposer was looping 4x re-writing the same epic
on every dispatch. Two halves to the fix:

- Pass completionSignal: "<promise>COMPLETE</promise>" explicitly on
  all three run() calls (decompose, implementer, reviewer). Makes the
  contract visible alongside maxIterations instead of relying on
  sandcastle's default.
- Append a "Signal completion (required)" section to each prompt
  telling the agent to emit the literal marker as its final line when
  the work is genuinely done, plus a "do NOT emit if..." list to
  discourage premature signaling.
This commit is contained in:
2026-05-13 19:11:44 +02:00
parent d6bf2f638f
commit eadbb7ebd9
5 changed files with 47 additions and 0 deletions

View File

@@ -79,3 +79,11 @@ Return structured JSON:
```
If you reject, the orchestrator passes your notes back to the implementer for a fix-up cycle (up to the task's `max-attempts`, default 3).
## Signal completion (required)
After you have returned the structured JSON decision, emit the literal string `<promise>COMPLETE</promise>` as the final line of your response.
Sandcastle uses this marker to stop the iteration loop. Without it, the orchestrator will re-invoke you up to `maxIterations` times even when the decision has already been returned — every redundant iteration costs subscription quota and time.
Emit the marker for BOTH `approve` and `reject` decisions — the decision is itself a terminal output, regardless of which way it went. Do NOT emit the marker if you still need to read more of the diff, run a tool, or otherwise have unfinished work.