fix(#222): enforce research synthesizer write-only summary contract (#240)

This commit is contained in:
Tom Boucher
2026-05-24 19:19:50 -04:00
committed by GitHub
parent e95fa8ad7d
commit a512bd79d7
3 changed files with 71 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 222
---
**`gsd-research-synthesizer` now hard-enforces Write-tool SUMMARY creation semantics** — Step 6 now declares SUMMARY.md-on-disk as canonical output and adds explicit hard rules against returning content in the response, permission-asking, and heredoc fallback. This closes the intermittent hallucinated write-restriction failure mode reported in #222. (#222)

View File

@@ -128,11 +128,19 @@ Identify gaps that couldn't be resolved and need attention during planning.
## Step 6: Write SUMMARY.md
**ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
**This is the canonical output of this agent. The orchestrator depends on `.planning/research/SUMMARY.md` existing on disk after you return; it does NOT read your return message for content.**
**Hard rules (must follow):**
1. **Use the `Write` tool** to write the file. The `Write` tool is in your `tools:` allowlist; there are no restrictions on it. Do not assume restrictions that the frontmatter does not impose.
2. **Do NOT return the SUMMARY.md content in your response.** Your return message is a brief confirmation (see `<structured_returns>` below); the content lives on disk.
3. **Do NOT ask permission to write.** Writing `.planning/research/SUMMARY.md` is the explicit purpose of this agent. Asking the orchestrator to do it instead is a failure mode that can cause downstream `SUMMARY.md not found` failures.
4. **Do NOT use `Bash(cat << 'EOF')` or heredoc** for file creation. Use the `Write` tool.
5. **If the Write tool errors,** surface the actual error in your return message. Do not silently fall back to returning content; that hides the failure from the orchestrator.
Use template: ~/.claude/get-shit-done/templates/research-project/SUMMARY.md
Write to `.planning/research/SUMMARY.md`
Write to `.planning/research/SUMMARY.md`.
## Step 7: Commit All Research

View File

@@ -0,0 +1,56 @@
// allow-test-rule: source-text-is-the-product
'use strict';
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const REPO_ROOT = path.resolve(__dirname, '..');
const SYNTHESIZER_PATH = path.join(REPO_ROOT, 'agents', 'gsd-research-synthesizer.md');
function readSynthesizerPrompt() {
return fs.readFileSync(SYNTHESIZER_PATH, 'utf8');
}
describe('bug #222: research synthesizer must write SUMMARY.md via Write tool', () => {
test('step 6 has explicit hard-rule block forbidding return-message content fallback', () => {
const prompt = readSynthesizerPrompt();
assert.match(
prompt,
/canonical output of this agent[\s\S]*existing on disk after you return/i,
'Step 6 must define SUMMARY.md-on-disk as canonical output.'
);
assert.match(
prompt,
/Hard rules \(must follow\):/i,
'Step 6 must contain explicit hard rules block.'
);
assert.match(
prompt,
/Use the `Write` tool[\s\S]*there are no restrictions/i,
'Rule 1 must force Write tool usage and reject hallucinated restrictions.'
);
assert.match(
prompt,
/Do NOT return the SUMMARY\.md content in your response/i,
'Rule 2 must forbid returning SUMMARY content in the response body.'
);
assert.match(
prompt,
/Do NOT ask permission to write/i,
'Rule 3 must forbid write-permission asks for this agent.'
);
assert.match(
prompt,
/Do NOT use `Bash\(cat << 'EOF'\)` or heredoc/i,
'Rule 4 must forbid heredoc/Bash file creation fallback.'
);
assert.match(
prompt,
/If the Write tool errors[\s\S]*Do not silently fall back to returning content/i,
'Rule 5 must force explicit error reporting for Write failures.'
);
});
});