fix(review): one reviewer's two findings on one triplet keep a row each
Pass 1 merged two different /code-review findings on (bin/slug.mjs, 46, CODE_REVIEW_DEFECT) and the second lost its row and its action. A reviewer never duplicates itself: its second finding on a triplet under another title stays its own row, with the id over rule_key#2 (the form critic-diff already uses); fill-finding-ids counts the same way (voyage-lekerepo trial 5, finding 7). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
16d1bb7dd5
commit
b47cabdf30
6 changed files with 112 additions and 23 deletions
|
|
@ -9,6 +9,7 @@ import { strict as assert } from 'node:assert';
|
|||
import { readFileSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { computeFindingId } from '../../lib/parsers/finding-id.mjs';
|
||||
import {
|
||||
severityRank,
|
||||
ingest,
|
||||
|
|
@ -58,6 +59,21 @@ test('dedupByTriplet — survivor is the highest-severity finding in the group',
|
|||
assert.equal(out[0].severity, 'BLOCKER');
|
||||
});
|
||||
|
||||
test('dedupByTriplet — two DIFFERENT findings from one reviewer on one triplet stay two rows with their own ids (trial 5, finding 7)', () => {
|
||||
// /code-review gave both the catch-all key at bin/slug.mjs:46; one merged row lost the second finding's action.
|
||||
const findings = [
|
||||
{ file: 'bin/slug.mjs', line: 46, rule_key: 'CODE_REVIEW_DEFECT', severity: 'MAJOR', title: 'EAGAIN on a non-blocking stdin', recommended_action: 'Read stdin with a stream.', reviewer: 'claude-code-review' },
|
||||
{ file: 'bin/slug.mjs', line: 46, rule_key: 'CODE_REVIEW_DEFECT', severity: 'MAJOR', title: 'A lone \\r does not split lines', recommended_action: 'Split on \\r too.', reviewer: 'claude-code-review' },
|
||||
{ file: 'bin/slug.mjs', line: 46, rule_key: 'CODE_REVIEW_DEFECT', severity: 'MAJOR', title: 'EAGAIN on a non-blocking stdin', recommended_action: 'Read stdin with a stream.', reviewer: 'code-correctness-reviewer' },
|
||||
];
|
||||
const out = dedupByTriplet(findings);
|
||||
assert.equal(out.length, 2, JSON.stringify(out.map((f) => f.title)));
|
||||
assert.deepEqual(out.map((f) => f.recommended_action), ['Read stdin with a stream.', 'Split on \\r too.']);
|
||||
assert.equal(out[0].id, computeFindingId('bin/slug.mjs', 46, 'CODE_REVIEW_DEFECT'));
|
||||
assert.equal(out[1].id, computeFindingId('bin/slug.mjs', 46, 'CODE_REVIEW_DEFECT#2'));
|
||||
assert.deepEqual([...out[0].raised_by].sort(), ['claude-code-review', 'code-correctness-reviewer']);
|
||||
});
|
||||
|
||||
test('dedupByTriplet — severity tie breaks toward the conformance reviewer', () => {
|
||||
const findings = [
|
||||
{ file: 'x.mjs', line: 1, rule_key: 'NON_GOAL_VIOLATED', severity: 'BLOCKER', title: 'corr', reviewer: 'correctness' },
|
||||
|
|
@ -403,3 +419,11 @@ test('runContract — a BLOCKER with a 900-character detail survives and yields
|
|||
assert.equal(result.findings[0].detail, detail, 'its detail is not cut');
|
||||
assert.equal(result.unverified.length, 0);
|
||||
});
|
||||
|
||||
test('the coordinator prose says one reviewer never duplicates itself, as dedupByTriplet does (trial 5, finding 7)', () => {
|
||||
const prose = readFileSync(join(ROOT, 'agents/review-coordinator.md'), 'utf8');
|
||||
const pass1 = prose.slice(prose.indexOf('### Pass 1'), prose.indexOf('### Pass 2'));
|
||||
assert.match(pass1, /one reviewer never duplicates itself/i);
|
||||
assert.match(pass1, /different titles are two\s+findings/);
|
||||
assert.match(prose, /k-th row on one triplet\s+gets it over `rule_key#k`/);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -145,6 +145,17 @@ test('fill-finding-ids: every @@ID_n@@ becomes the id computed over (file, line,
|
|||
assert.match(r.text, new RegExp(`"id": "${id1}"`));
|
||||
});
|
||||
|
||||
test('fill-finding-ids: a second finding on the same (file, line, rule_key) gets its own id, `#2` on the rule (trial 5, finding 7)', () => {
|
||||
const G = { ...F1, title: 'A lone \\r does not split lines' };
|
||||
const r = fillFindingIds(review([F1, G]));
|
||||
assert.equal(r.ok, true, r.errors.join('\n'));
|
||||
const id1 = computeFindingId(F1.file, F1.line, F1.rule_key);
|
||||
const id2 = computeFindingId(F1.file, F1.line, `${F1.rule_key}#2`);
|
||||
assert.notEqual(id1, id2);
|
||||
assert.match(r.text, new RegExp(`findings:\\n - ${id1}\\n - ${id2}\\n`));
|
||||
assert.equal(fillFindingIds(r.text).ok, true, 'the filled review checks out again');
|
||||
});
|
||||
|
||||
test('fill-finding-ids: a placeholder with no JSON finding behind it is an error, not a guess', () => {
|
||||
const r = fillFindingIds(review([F1], 'See also @@ID_7@@.'));
|
||||
assert.equal(r.ok, false);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue