prompt(atlas): replace retry cap with no-excuses policy and add boulder-complete response

Drops 'Maximum 3 retries' / 'document and move on' across every Atlas
variant (default, opus-4-7, gpt, kimi, gemini). New text forbids the
'false positive' excuse explicitly and instructs Atlas to keep iterating
on the same task_id, attaching a diagnosis plan, until verification
passes — and to spawn a different-angle subagent only when the original
loops.

Adds a shared <boulder_completion_response> section composed by
shared-prompt.ts. When the hook injects the BOULDER COMPLETE nudge,
Atlas now knows to print TOTAL ELAPSED + per-task elapsed times in the
exact summary shape, confirm boulder.json state, and only mark
pass-final-wave after the Final Wave reviewers approve.
This commit is contained in:
YeonGyu-Kim
2026-05-11 13:32:27 +09:00
parent 5d823b5078
commit 8c238a11a2
7 changed files with 127 additions and 25 deletions
+65
View File
@@ -127,3 +127,68 @@ describe("Atlas prompts use task_id (not session_id) for retries", () => {
}
})
})
describe("Atlas prompts no-excuses retry policy", () => {
test("no variant contains a numeric retry cap", () => {
for (const [name, prompt] of ALL_VARIANTS) {
expect(prompt, `${name}: must not impose Maximum N retries`).not.toMatch(/maximum\s+\d+\s+retr/i)
expect(prompt, `${name}: must not impose N retries per task`).not.toMatch(/\d+\s+retries\s+per\s+task/i)
expect(prompt, `${name}: must not impose N retry attempts`).not.toMatch(/\d+\s+retry\s+attempts/i)
}
})
test("no variant tells Atlas to move on after failure", () => {
for (const [name, prompt] of ALL_VARIANTS) {
const lower = prompt.toLowerCase()
expect(lower, `${name}: must not tell Atlas to skip failed tasks`).not.toContain("document and continue to independent tasks")
expect(lower, `${name}: must not tell Atlas to move to next independent task`).not.toContain("document and move to next independent task")
expect(lower, `${name}: must not tell Atlas to move on`).not.toContain("then document and move on")
}
})
test("all variants forbid the false-positive excuse explicitly", () => {
for (const [name, prompt] of ALL_VARIANTS) {
const lower = prompt.toLowerCase()
expect(lower, `${name}: missing false positive prohibition`).toContain("false positive")
expect(lower, `${name}: missing no-retry-cap statement`).toContain("no retry cap")
}
})
test("all variants instruct subagent re-call with different angle when looping", () => {
for (const [name, prompt] of ALL_VARIANTS) {
const lower = prompt.toLowerCase()
expect(lower, `${name}: missing different-angle subagent instruction`).toMatch(/different angle|new subagent/)
}
})
})
describe("Atlas prompts boulder-completion response", () => {
test("all variants document the boulder-complete nudge response", () => {
for (const [name, prompt] of ALL_VARIANTS) {
expect(prompt, `${name}: missing boulder_completion_response section`).toContain("<boulder_completion_response>")
expect(prompt, `${name}: missing BOULDER COMPLETE recognition phrase`).toContain("BOULDER COMPLETE")
expect(prompt, `${name}: missing TOTAL ELAPSED summary field`).toContain("TOTAL ELAPSED")
expect(prompt, `${name}: missing PER-TASK ELAPSED summary field`).toContain("PER-TASK ELAPSED")
}
})
test("all variants explain the one-shot nudge guarantee", () => {
for (const [name, prompt] of ALL_VARIANTS) {
const lower = prompt.toLowerCase()
expect(lower, `${name}: missing one-shot nudge guarantee`).toMatch(/at most once|fires.*once/)
}
})
test("boulder completion section appears after the workflow", () => {
for (const [name, prompt] of ALL_VARIANTS) {
const workflowIdx = prompt.indexOf("<workflow>")
const completionIdx = prompt.indexOf("<boulder_completion_response>")
expect(workflowIdx, `${name}: missing workflow section`).toBeGreaterThan(-1)
expect(completionIdx, `${name}: missing boulder completion section`).toBeGreaterThan(-1)
expect(
completionIdx,
`${name}: boulder completion must come AFTER the workflow so the agent reads the failure rules first`,
).toBeGreaterThan(workflowIdx)
}
})
})
+12 -8
View File
@@ -142,24 +142,28 @@ task(
)
\`\`\`
### 3.5 Handle Failures (USE task_id)
### 3.5 Handle Failures (USE task_id, NEVER GIVE UP)
Every \`task()\` output includes a task_id. STORE IT.
If task fails:
1. Identify what went wrong
2. **Resume the SAME session** - subagent has full context already:
**Failure is never an excuse to stop or skip.** A subagent that reports success when verification fails is wrong, not "experiencing a false positive". "False positive" is not a valid reason in this codebase. If verification fails, the work is unfinished. There is no retry cap.
When a task fails:
1. Diagnose what actually broke. Read the error, read the file, do not guess.
2. **Resume the SAME session** so the subagent keeps its full context:
\`\`\`typescript
task(
task_id="ses_xyz789",
load_skills=[...],
prompt="FAILED: {error}. Fix by: {specific instruction}"
prompt="FAILED: {actual error output}. Diagnosis: {what you observed}. Fix by: {specific instruction}"
)
\`\`\`
3. Maximum 3 retry attempts with the SAME session
4. If blocked after 3 attempts: Document and continue to independent tasks
3. If a single retry on the same session does not fix it, **plan the diagnosis explicitly**. Write down what the subagent attempted, what it observed, what hypothesis you have. Then resume the same session with that plan attached. Iterate until verification passes.
4. If the subagent itself is the bottleneck (looping on the same broken approach), spawn a NEW subagent with a different angle. Pass the failed attempts as context so it does not repeat them. Stay on the same plan task; never move on with that task unverified.
**Why task_id is MANDATORY for failures:** subagent already read all files, knows what was tried, what failed. Starting fresh wipes that. 70%+ token savings on retries.
**Why task_id is MANDATORY:** the subagent already read every relevant file, knows what was tried, and knows what failed. Starting fresh discards that and costs ~3-4× more tokens. Use \`task_id\` for retries and for asking the same subagent to plan its own diagnosis.
**Why no excuses:** the user requires every task to complete. Documenting a failure and moving on produces a partial plan that will fail Final Wave review. Verification is the gate. Push through it.
### 3.6 Loop Until Implementation Complete
+3 -4
View File
@@ -162,16 +162,15 @@ Read(".sisyphus/plans/{plan-name}.md")
\`\`\`
Count remaining **top-level task** checkboxes. Ignore nested verification/evidence checkboxes.
### 3.5 Handle Failures
### 3.5 Handle Failures (NEVER GIVE UP)
**CRITICAL: Use \`task_id\` for retries.**
\`\`\`typescript
task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}")
task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {actual error}. Diagnosis: {what you observed}. Fix by: {instruction}")
\`\`\`
- Maximum 3 retries per task
- If blocked: document and continue to next independent task
**Failure is never an excuse to stop or skip.** A subagent reporting success when verification fails is wrong, not "experiencing a false positive". "False positive" is not a valid reason in this codebase. There is no retry cap. Diagnose, attach a plan, resume the same session until verification passes. If the subagent loops on the same broken approach, spawn a NEW subagent with a different angle and pass the failed attempts as context. Never move on with a task unverified.
### 3.6 Loop Until Implementation Complete
+3 -3
View File
@@ -125,13 +125,13 @@ Read(".sisyphus/plans/{plan-name}.md")
\`\`\`
Count remaining **top-level task** checkboxes (ignore nested verification/evidence checkboxes). Ground truth.
### 3.5 Handle Failures (USE task_id)
### 3.5 Handle Failures (USE task_id, NEVER GIVE UP)
\`\`\`typescript
task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {instruction}")
task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {actual error}. Diagnosis: {what you observed}. Fix by: {instruction}")
\`\`\`
Maximum 3 retries on the same session. Then document and move to next independent task.
**Failure is never an excuse to stop or skip.** A subagent reporting success when verification fails is wrong, not "experiencing a false positive". "False positive" is not a valid reason in this codebase. There is no retry cap. Diagnose, attach a plan, resume the same session until verification passes. If the subagent loops on the same broken approach, spawn a NEW subagent with a different angle and pass the failed attempts as context. Never move on with a task unverified.
### 3.6 Loop Until Implementation Complete
+3 -3
View File
@@ -127,13 +127,13 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden
**If verification fails**: resume the SAME session via \`task_id\`. Do not start fresh.
### 3.5 Handle Failures (USE task_id)
### 3.5 Handle Failures (USE task_id, NEVER GIVE UP)
\`\`\`typescript
task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {error}. Fix by: {specific instruction}")
task(task_id="ses_xyz789", load_skills=[...], prompt="FAILED: {actual error}. Diagnosis: {what you observed}. Fix by: {specific instruction}")
\`\`\`
Maximum 3 retries on the same session. Then document and move on.
**Failure is never an excuse to stop or skip.** A subagent reporting success when verification fails is wrong, not "experiencing a false positive". "False positive" is not a valid reason in this codebase. There is no retry cap. Diagnose, attach a plan, resume the same session until verification passes. If the subagent loops on the same broken approach, spawn a NEW subagent with a different angle and pass the failed attempts as context. Never move on with a task unverified.
### 3.6 Loop Until Implementation Complete
+9 -7
View File
@@ -134,17 +134,19 @@ Count remaining **top-level task** checkboxes. Ignore nested verification/eviden
task(task_id="ses_xyz789", load_skills=[...], prompt="Verification failed: {actual error}. Fix.")
\`\`\`
### 3.5 Handle Failures (USE task_id)
### 3.5 Handle Failures (USE task_id, NEVER GIVE UP)
Every \`task()\` output includes a task_id. STORE IT.
If task fails:
1. Identify what went wrong
2. Resume the SAME session via \`task_id\` (subagent already has full context)
3. Maximum 3 retry attempts on the same session
4. If still blocked: document and continue to independent tasks
**Failure is never an excuse to stop or skip.** A subagent that reports success when verification fails is wrong, not "experiencing a false positive". "False positive" is not a valid reason in this codebase. If verification fails, the work is unfinished. There is no retry cap.
**NEVER start fresh on failures** — wipes accumulated context, costs ~3-4× more tokens.
When a task fails:
1. Diagnose what actually broke. Read the error, read the file, do not guess.
2. Resume the SAME session via \`task_id\` (subagent already has full context).
3. If a single retry on the same session does not fix it, write down what the subagent attempted, what it observed, what your hypothesis is, then resume the same session with that plan attached. Iterate until verification passes.
4. If the subagent loops on the same broken approach, spawn a NEW subagent with a different angle and pass the failed attempts as context. Stay on the same plan task; never move on with that task unverified.
**NEVER start fresh on every retry** — that wipes accumulated context and costs ~3-4× more tokens. Reserve fresh sessions for a deliberately different angle.
### 3.6 Loop Until Implementation Complete
+32
View File
@@ -186,6 +186,36 @@ After EVERY verified task() completion, you MUST:
This ensures accurate progress tracking. Skip this and you lose visibility into what remains.
</post_delegation_rule>`
const ATLAS_BOULDER_COMPLETION_RESPONSE = `<boulder_completion_response>
## When the Boulder-Complete Nudge Arrives
The system injects ONE nudge into your session when every top-level checkbox in the active plan flips to \`- [x]\`. That nudge carries the total elapsed time and a per-task breakdown for the active boulder. Recognize it by the phrase "BOULDER COMPLETE" near the top of the injected message.
When you see that nudge:
1. In your next turn, print the final orchestration summary using this exact shape:
\`\`\`
ORCHESTRATION COMPLETE
PLAN: {plan-name}
TOTAL ELAPSED: {total elapsed, human readable}
TASKS COMPLETED: {N}/{N}
PER-TASK ELAPSED:
- {label} {title}: {elapsed}
- {label} {title}: {elapsed}
FINAL WAVE: F1 [...] | F2 [...] | F3 [...] | F4 [...]
\`\`\`
2. Confirm via your tools that the active work in \`.sisyphus/boulder.json\` now has \`status: "completed"\` and \`elapsed_ms\` populated. The hook calls \`completeBoulder()\` for you; you are reading state, not writing it.
3. Mark the \`pass-final-wave\` todo as \`completed\` only after the Final Verification Wave reviewers all APPROVE. If the wave has not run yet, run it now in parallel; the boulder-complete nudge does not bypass it.
The nudge fires at most once per work. If you missed it (compaction, session restart), read \`boulder.json\` yourself, compute the same summary from \`started_at\`, \`ended_at\`, and \`task_sessions[*].elapsed_ms\`, and print it.
</boulder_completion_response>`
export function buildAtlasPrompt(sections: AtlasPromptSections): string {
const addendum = sections.parallelAddendum.trim().length > 0 ? `\n\n${sections.parallelAddendum}` : ""
@@ -210,5 +240,7 @@ ${sections.boundaries}
${sections.criticalRules}
${ATLAS_POST_DELEGATION_RULE}
${ATLAS_BOULDER_COMPLETION_RESPONSE}
`
}