diff --git a/agents/implementer-agent.md b/agents/implementer-agent.md index ecb441e..a1b066a 100644 --- a/agents/implementer-agent.md +++ b/agents/implementer-agent.md @@ -146,6 +146,11 @@ Move content from one file to another. Append to: `~/.claude/config-audit/sessions/{session-id}/implementation-log.md` +**Append discipline (shared log):** other implementer agents may be writing this +log concurrently. ALWAYS append your entry with a Bash `>>` heredoc; +NEVER use the Write or Edit tool on the log file — a full-file Write silently +clobbers entries other agents appended after you read the file. + ### Success ```markdown diff --git a/commands/implement.md b/commands/implement.md index 5f13d51..f2ff97a 100644 --- a/commands/implement.md +++ b/commands/implement.md @@ -78,6 +78,8 @@ Agent(subagent_type: "config-audit:implementer-agent") fields from the action plan (the planner already rendered them) — do not re-derive severity prose. Append result to: ~/.claude/config-audit/sessions/{session-id}/implementation-log.md + Append with Bash `>>` (heredoc) — NEVER the Write tool on this log; + parallel agents share it and a full-file Write clobbers their entries. ``` Show progress between groups using the humanized titles already present in the action plan: diff --git a/tests/commands/implement-log-append.test.mjs b/tests/commands/implement-log-append.test.mjs new file mode 100644 index 0000000..09f0d6c --- /dev/null +++ b/tests/commands/implement-log-append.test.mjs @@ -0,0 +1,41 @@ +/** + * M-BUG-20 — shared implementation-log clobbering under parallel agents. + * + * implement.md step 4 spawns implementer agents in parallel batches, and every + * agent appends its result to the SAME implementation-log.md. Dogfooding + * (2026-07-17, throwaway linkedin-posts copy) showed agents satisfying + * "Append result to:" with a full-file Write: each agent read the log, added + * its entry, and wrote the whole file back — the last writer silently + * clobbered 4 of 6 entries. + * + * Contract: both the command template and the agent prompt must pin the append + * mechanism — Bash `>>`, never the Write/Edit tool — on the shared log. + */ + +import { test } from 'node:test'; +import { strict as assert } from 'node:assert'; +import { readFile } from 'node:fs/promises'; +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = resolve(__dirname, '..', '..'); + +const APPEND_MECHANISM_REGEX = />>/; +const FORBID_WRITE_TOOL_REGEX = /never[^.\n]*\bwrite\b[^.\n]*tool|\bwrite\b[^.\n]*tool[^.\n]*never/i; + +test('implement.md: agent-spawn template pins Bash >> append on the shared log', async () => { + const content = await readFile(resolve(ROOT, 'commands', 'implement.md'), 'utf-8'); + assert.match(content, APPEND_MECHANISM_REGEX, + 'implement.md must instruct appending to implementation-log.md with Bash >>'); + assert.match(content, FORBID_WRITE_TOOL_REGEX, + 'implement.md must forbid the Write tool on the shared implementation log'); +}); + +test('implementer-agent.md: output section pins Bash >> append and forbids Write tool on the log', async () => { + const content = await readFile(resolve(ROOT, 'agents', 'implementer-agent.md'), 'utf-8'); + assert.match(content, APPEND_MECHANISM_REGEX, + 'implementer-agent.md must instruct appending to the log with Bash >>'); + assert.match(content, FORBID_WRITE_TOOL_REGEX, + 'implementer-agent.md must forbid the Write tool on the shared implementation log'); +});