fix(acr): analyze persists agent-returned report (M-BUG-18)
The Claude Code subagent harness instructs spawned agents NOT to write report/summary/findings/analysis .md files — the parent reads the final text message. Verified live: analyzer-agent skipped Write entirely and returned the report inline, so analysis-report.md never landed on disk and the plan/interview/status phases would find nothing to read. New contract (orchestrator-writes pattern): analyzer-agent returns the complete report as its final message; the analyze command saves it verbatim to the session directory before presenting the summary. Same class exists in plan/feature-gap/optimize/scanner agent pairs — deliberately left for their own dogfood chunks (plan is judged as-is first per the pipeline sequence). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CTontYwY5JGS4nL2AuiASy
This commit is contained in:
parent
69a4654dd7
commit
4b7b2d9c48
3 changed files with 83 additions and 7 deletions
|
|
@ -51,11 +51,16 @@ In `--raw` mode, fall back to v5.0.0 severity prefiks and verbatim scanner title
|
|||
5. **Identify optimizations**: Rules to globalize, missing configs, orphaned files
|
||||
6. **Security scan**: Aggregate secret warnings, check for insecure patterns
|
||||
7. **CLAUDE.md quality assessment**: Score each file against rubric, assign letter grades
|
||||
8. **Generate report**: Write comprehensive markdown report — group findings by `userImpactCategory`, lead with `userActionLanguage`
|
||||
8. **Generate report**: Compose the comprehensive markdown report — group findings by `userImpactCategory`, lead with `userActionLanguage`
|
||||
|
||||
## Output
|
||||
|
||||
Write to: `~/.claude/config-audit/sessions/{session-id}/analysis-report.md`
|
||||
Return the complete report as your final message — do not write it to a file
|
||||
yourself. The Claude Code subagent harness instructs agents not to write
|
||||
report/analysis files; your text output IS the deliverable. The orchestrating
|
||||
command saves your returned report verbatim to
|
||||
`~/.claude/config-audit/sessions/{session-id}/analysis-report.md` for the
|
||||
downstream plan/interview/status phases.
|
||||
|
||||
**Output MUST NOT exceed 300 lines.** Prioritize findings by severity. Use tables, not prose.
|
||||
|
||||
|
|
@ -183,4 +188,4 @@ Verify report: all findings referenced, recommendations actionable, severity lev
|
|||
|
||||
- Process findings in memory (typically < 1MB total)
|
||||
- Generate report in single pass
|
||||
- No file modifications (read-only except report output)
|
||||
- No file modifications (read-only; the report is returned as your final message)
|
||||
|
|
|
|||
|
|
@ -60,12 +60,21 @@ Agent(subagent_type: "config-audit:analyzer-agent")
|
|||
raw severity. The humanizer already replaced jargon-heavy
|
||||
title/description/recommendation strings with plain-language
|
||||
equivalents — render them verbatim, do not paraphrase.
|
||||
Output to: ~/.claude/config-audit/sessions/{session-id}/analysis-report.md
|
||||
Return the complete report as your final message. Do not write it
|
||||
to a file — the orchestrating command saves it to the session directory.
|
||||
```
|
||||
|
||||
### Step 4: Present summary
|
||||
### Step 4: Save the report
|
||||
|
||||
After the agent completes, read the generated report and show a brief summary:
|
||||
The agent returns the complete report as its final message — the Claude Code
|
||||
subagent harness instructs agents not to write report/analysis files themselves,
|
||||
so the command must persist it. Write the returned report verbatim (no edits,
|
||||
no truncation) to `~/.claude/config-audit/sessions/{session-id}/analysis-report.md`
|
||||
using the Write tool. Downstream phases (`plan`, `interview`, `status`) read this file.
|
||||
|
||||
### Step 5: Present summary
|
||||
|
||||
After saving the report, show a brief summary:
|
||||
|
||||
```markdown
|
||||
### Analysis Complete
|
||||
|
|
@ -84,6 +93,6 @@ Full report: `~/.claude/config-audit/sessions/{session-id}/analysis-report.md`
|
|||
- **`/config-audit fix`** — Auto-fix deterministic issues right away
|
||||
```
|
||||
|
||||
### Step 5: Update state
|
||||
### Step 6: Update state
|
||||
|
||||
Update `state.yaml` with `current_phase: "analyze"`, `next_phase: "plan"`.
|
||||
|
|
|
|||
62
tests/commands/analyze-report-persistence.test.mjs
Normal file
62
tests/commands/analyze-report-persistence.test.mjs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* M-BUG-18 — analysis-report.md persistence contract.
|
||||
*
|
||||
* The Claude Code subagent harness instructs spawned agents NOT to write
|
||||
* report/summary/findings/analysis .md files — the parent reads the agent's
|
||||
* final text message, not files it creates. The analyzer-agent therefore
|
||||
* cannot be the one that persists analysis-report.md (verified live: the
|
||||
* agent skipped Write and returned the report inline).
|
||||
*
|
||||
* New contract (orchestrator-writes pattern):
|
||||
* - analyzer-agent returns the complete report as its final message
|
||||
* - the analyze command saves that returned report verbatim to
|
||||
* ~/.claude/config-audit/sessions/{session-id}/analysis-report.md,
|
||||
* which downstream phases (plan, interview, status) read.
|
||||
*/
|
||||
|
||||
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 COMMANDS_DIR = resolve(__dirname, '..', '..', 'commands');
|
||||
const AGENTS_DIR = resolve(__dirname, '..', '..', 'agents');
|
||||
|
||||
test('analyze.md: agent prompt does not tell the agent to write the report file', async () => {
|
||||
const content = await readFile(resolve(COMMANDS_DIR, 'analyze.md'), 'utf-8');
|
||||
assert.doesNotMatch(
|
||||
content,
|
||||
/Output to:.*analysis-report\.md/,
|
||||
'the spawn prompt must not instruct the subagent to write analysis-report.md — the harness blocks agent-written report files'
|
||||
);
|
||||
});
|
||||
|
||||
test('analyze.md: command saves the returned report to analysis-report.md', async () => {
|
||||
const content = await readFile(resolve(COMMANDS_DIR, 'analyze.md'), 'utf-8');
|
||||
assert.match(
|
||||
content,
|
||||
/return[s]? the complete report as (its|your) final message/i,
|
||||
'analyze.md must state that the agent returns the report inline'
|
||||
);
|
||||
assert.match(
|
||||
content,
|
||||
/Write tool[\s\S]{0,200}analysis-report\.md|analysis-report\.md[\s\S]{0,200}Write tool/,
|
||||
'analyze.md must instruct the command to persist the returned report to analysis-report.md with the Write tool'
|
||||
);
|
||||
});
|
||||
|
||||
test('analyzer-agent.md: output contract is return-inline, not self-write', async () => {
|
||||
const content = await readFile(resolve(AGENTS_DIR, 'analyzer-agent.md'), 'utf-8');
|
||||
assert.match(
|
||||
content,
|
||||
/return the complete report as your final message/i,
|
||||
'analyzer-agent must be told its final message IS the report'
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
content,
|
||||
/^Write to: .*analysis-report\.md/m,
|
||||
'analyzer-agent must not carry the old self-write output contract'
|
||||
);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue