fix(review): changed code and instruction files get deep review by default, summary-only is for docs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-23 15:37:39 +02:00
commit 761f406faa
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
6 changed files with 75 additions and 8 deletions

View file

@ -565,7 +565,7 @@ The history is the `review.md` files your repo already has; no new store.
### Triage gate (deterministic)
A path-pattern classifier produces `{file → deep-review|summary-only|skip}` before any LLM runs. Hardcoded skip patterns: `*.lock`, `*.svg`, `dist/**`, `build/**`, `node_modules/**`, generated markers. Deep-review patterns: `auth/**`, `crypto/**`, `**/security/**`. Hard refuse-with-suggestion above 100 files / 100K diff tokens.
A path-pattern classifier produces `{file → deep-review|summary-only|skip}` before any LLM runs. Hardcoded skip patterns: `*.lock`, `*.svg`, `dist/**`, `build/**`, `node_modules/**`, generated markers. `deep-review`: default for every changed file not in the other two rows — code, tests, `commands/`, `agents/`, `skills/` Markdown, and the instruction files `CLAUDE.md`, `AGENTS.md` and `.claude/rules/**`. `summary-only`: `docs/**`, Markdown files at the repo root other than `CLAUDE.md` and `AGENTS.md` (README, CHANGELOG), `tests/fixtures/**`. Hard refuse-with-suggestion above 100 files / 100K diff tokens.
### Feedback loop (Handover 6)

View file

@ -123,8 +123,8 @@ produces a treatment map:
| Treatment | When |
|-----------|------|
| `skip` | Matches `*.lock`, `*.svg`, `dist/**`, `build/**`, `node_modules/**`, generated-file marker present in first 3 lines |
| `deep-review` | Matches `auth/**`, `crypto/**`, `**/security/**`, `hooks/**` |
| `summary-only` | Default treatment for everything else |
| `deep-review` | Default for every changed file not in the other two rows — code, tests, `commands/`, `agents/`, `skills/` Markdown, and the instruction files `CLAUDE.md`, `AGENTS.md` and `.claude/rules/**` |
| `summary-only` | `docs/**`, Markdown files at the repo root other than `CLAUDE.md` and `AGENTS.md` (README, CHANGELOG), `tests/fixtures/**` |
Hard refuse-with-suggestion gates (use AskUserQuestion):
- > 100 files in the diff

View file

@ -184,8 +184,8 @@ every file from Phase 3 into a treatment bucket:
| Treatment | When |
|-----------|------|
| `skip` | Matches `*.lock`, `*.svg`, `dist/**`, `build/**`, `node_modules/**`, OR the file's first 3 lines contain a generated-file marker (`@generated`, `Code generated by`, `DO NOT EDIT`). |
| `deep-review` | Matches `auth/**`, `crypto/**`, `**/security/**`, `hooks/**`. |
| `summary-only` | Default treatment for everything else. |
| `deep-review` | Default for every changed file not in the other two rows — code, tests, `commands/`, `agents/`, `skills/` Markdown, and the instruction files `CLAUDE.md`, `AGENTS.md` and `.claude/rules/**`. |
| `summary-only` | `docs/**`, Markdown files at the repo root other than `CLAUDE.md` and `AGENTS.md` (README, CHANGELOG), `tests/fixtures/**`. |
Hard refuse-with-suggestion gates — use `AskUserQuestion`:

View file

@ -187,7 +187,7 @@ function reviewerPrompt(kind, a) {
'Only emit findings whose rule_key is in the catalogue. Cite file:line from the diff.',
'',
'=== TRIAGE MAP (respect skip decisions) ===',
a.triage || '(no triage map supplied — treat all changed files as summary-only)',
a.triage || '(no triage map supplied — deep-review every changed file except docs/**, root Markdown other than CLAUDE.md and AGENTS.md, and tests/fixtures/**)',
].join('\n');
}

View file

@ -27,8 +27,8 @@ should look at first.
| File | Treatment | Reason |
|------|-----------|--------|
| lib/foo.mjs | deep-review | matched deep-review pattern |
| lib/bar.mjs | summary-only | low-risk, no test patterns matched |
| lib/foo.mjs | deep-review | default for changed code |
| docs/guide.md | summary-only | docs/** is summary-only |
| dist/bundle.js | skip | matches generated-file pattern |
| commands/baz.md `[uncommitted]` | deep-review | working-tree change since session_start_sha |

View file

@ -1256,3 +1256,70 @@ test('[#113] sibling: agents/research-orchestrator.md', () => {
assert.ok(flat(read(RESEARCH_ORCH)).includes('| `contrarian-researcher` | Counter-evidence, overlooked alternatives, reasons to reconsider; runs in wave 2, against wave 1\'s leading answer |'),
'the agent table does not say the contrarian runs in wave 2');
});
// --- F9: changed code and instruction files get deep review by default ------
// The triage table made `summary-only` the default treatment for everything
// else, so changed code outside auth/crypto/security/hooks got a structural
// pass only. `deep-review` is now the default for every changed file not in
// the other two rows, the instruction files CLAUDE.md, AGENTS.md and
// .claude/rules/** among them; `summary-only` is for docs/**, root Markdown
// other than CLAUDE.md and AGENTS.md, and tests/fixtures/**. The four copies
// (command, orchestrator, README, workflow fallback, template rows) say the
// same; each is pinned by its own test against the phrase set below.
const REVIEW = 'commands/trekreview.md';
const F9_DEEP = 'for every changed file not in the other two rows — code, tests, `commands/`, `agents/`, `skills/` Markdown, and the instruction files `CLAUDE.md`, `AGENTS.md` and `.claude/rules/**`';
const F9_SUMMARY = '`docs/**`, Markdown files at the repo root other than `CLAUDE.md` and `AGENTS.md` (README, CHANGELOG), `tests/fixtures/**`';
const F9_OLD = /Default treatment for everything else/;
/** The one table row in `text` whose first cell is `cell`. */
function f9Row(text, cell) {
const hits = text.split('\n').filter((l) => l.startsWith(`| ${cell} |`));
assert.equal(hits.length, 1, `expected exactly one "${cell}" row; found ${hits.length}`);
return hits[0];
}
/** The deep-review and summary-only rows hold the phrase set; the old default is gone. */
function f9Table(text, where) {
assert.doesNotMatch(text, F9_OLD, `${where}: summary-only is still the default treatment for everything else`);
const deep = f9Row(text, '`deep-review`');
assert.match(deep, /\| Default for every changed file/, `${where}: the deep-review row does not name the default`);
assert.ok(deep.includes(F9_DEEP), `${where}: the deep-review row does not name code, tests and CLAUDE.md, AGENTS.md, .claude/rules/**`);
const summary = f9Row(text, '`summary-only`');
assert.ok(summary.includes(F9_SUMMARY), `${where}: the summary-only row is not docs/**, root Markdown, tests/fixtures/**`);
assert.doesNotMatch(summary, /[Dd]efault/, `${where}: the summary-only row still claims the default`);
assert.match(f9Row(text, '`skip`'), /Matches `\*\.lock`, `\*\.svg`, `dist\/\*\*`, `build\/\*\*`, `node_modules\/\*\*`/, `${where}: the skip row changed`);
}
test('[F9] the trekreview triage table makes deep-review the default, naming CLAUDE.md, AGENTS.md and .claude/rules/**; summary-only is for docs; the size gate is unchanged', () => {
const p4 = section(read(REVIEW), '## Phase 4 — Triage gate (deterministic path-pattern classifier)');
f9Table(p4, REVIEW);
assert.ok(p4.includes('if (reviewed_files_count > 100) → ask user'), 'the file-count gate changed');
assert.ok(p4.includes('if (estimated_diff_tokens > 100000) → ask user'), 'the diff-token gate changed');
});
test('[F9] sibling: agents/review-orchestrator.md', () => {
f9Table(section(read('agents/review-orchestrator.md'), '### Phase 4 — Triage gate (path-pattern classifier)'), 'agents/review-orchestrator.md');
});
test('[F9] sibling: README.md', () => {
const tri = flat(section(read('README.md'), '### Triage gate (deterministic)'));
assert.doesNotMatch(tri, /Deep-review patterns: `auth\/\*\*`, `crypto\/\*\*`, `\*\*\/security\/\*\*`\./, 'README.md still limits deep-review to auth/crypto/security');
assert.ok(tri.includes(`\`deep-review\`: default ${F9_DEEP}.`), 'README.md does not make deep-review the default with the instruction files');
assert.ok(tri.includes(`\`summary-only\`: ${F9_SUMMARY}.`), 'README.md does not limit summary-only to docs/**, root Markdown, tests/fixtures/**');
assert.ok(tri.includes('Hard refuse-with-suggestion above 100 files / 100K diff tokens.'), 'README.md size gate changed');
});
test('[F9] sibling: scripts/trekreview-armB.workflow.mjs', () => {
const text = read('scripts/trekreview-armB.workflow.mjs');
assert.doesNotMatch(text, /treat all changed files as summary-only/, 'the workflow fallback still treats every file as summary-only');
assert.ok(text.includes("a.triage || '(no triage map supplied — deep-review every changed file except docs/**, root Markdown other than CLAUDE.md and AGENTS.md, and tests/fixtures/**)',"),
'the workflow fallback does not deep-review every changed file except docs/**, root Markdown other than CLAUDE.md and AGENTS.md, and tests/fixtures/**');
});
test('[F9] sibling: templates/trekreview-template.md', () => {
const cov = section(read('templates/trekreview-template.md'), '## Coverage');
assert.doesNotMatch(cov, /matched deep-review pattern|no test patterns matched/, 'the template rows still show the old pattern reasons');
assert.ok(cov.includes('| lib/foo.mjs | deep-review | default for changed code |'), 'the template has no deep-review default row');
assert.ok(cov.includes('| docs/guide.md | summary-only | docs/** is summary-only |'), 'the template has no docs summary-only row');
});