fix(review): a past-the-end line makes a finding unverified, never refuted, and the Declined to Judge copy-through is pinned
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
761f406faa
commit
7175783ce5
4 changed files with 87 additions and 6 deletions
|
|
@ -1323,3 +1323,62 @@ test('[F9] sibling: templates/trekreview-template.md', () => {
|
|||
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');
|
||||
});
|
||||
|
||||
// --- CL: a line number alone never refutes a finding ------------------------
|
||||
// Pass 2's Accuracy row dropped a finding as refuted (`accuracy:refuted`) for an
|
||||
// "impossibly large line number", so a finding whose claim was never checked
|
||||
// weighed nothing and could not hold ALLOW back. Only a citation that escapes
|
||||
// the repo root or a negative line refutes; a line past the end of the file
|
||||
// makes the finding `unverified` (`accuracy:line-out-of-range`): the citation
|
||||
// is wrong, the claim is unchecked. The lib side is pinned in
|
||||
// tests/lib/coordinator-contract.test.mjs.
|
||||
//
|
||||
// --- DJ: the Declined to Judge copy-through is held -------------------------
|
||||
// A reviewer's own `### Declined to Judge` lines reach review.md only through
|
||||
// three sentences: /trekreview Phase 6 passes them to the coordinator, the
|
||||
// coordinator's Input names them, and body section 9 copies them. Each is
|
||||
// pinned by its own flattened regex. These pass at ab6b32c by design (no text
|
||||
// changed); the round's red script proves them red by deleting the sentences.
|
||||
|
||||
const COORD = 'agents/review-coordinator.md';
|
||||
|
||||
/** The one Pass 2 table row whose first cell is `Accuracy`. */
|
||||
function accuracyRow() {
|
||||
const p2 = section(read(COORD), '### Pass 2 — HubSpot Judge filters (3 criteria)');
|
||||
const hits = p2.split('\n').filter((l) => /^\| Accuracy \|/.test(l));
|
||||
assert.equal(hits.length, 1, `expected exactly one Accuracy row in Pass 2; found ${hits.length}`);
|
||||
return hits[0];
|
||||
}
|
||||
|
||||
test('[CL] the Accuracy row refutes only a root escape or a negative line; a line past the end is unverified (accuracy:line-out-of-range)', () => {
|
||||
const row = accuracyRow();
|
||||
assert.match(row, /dropped|accuracy:refuted/, 'control: the Accuracy row still drops something as refuted');
|
||||
for (const phrase of [/impossibly large line number/, /≤ file line count/]) {
|
||||
assert.doesNotMatch(row, phrase, `the Accuracy row still pairs ${phrase} with dropped / accuracy:refuted`);
|
||||
}
|
||||
assert.match(row, /Path traversal escape or negative line \| \*\*dropped\*\* \(`accuracy:refuted`\)/,
|
||||
'the Accuracy row does not drop exactly a root escape or a negative line as refuted');
|
||||
assert.match(row, /A line past the end of the file[^|]*the citation is wrong, the claim is unchecked[^|]*`unverified` \(`accuracy:line-out-of-range`\)/,
|
||||
'the Accuracy row does not send a line past the end of the file to unverified (accuracy:line-out-of-range)');
|
||||
const why = flat(section(read(COORD), '### Pass 2 — HubSpot Judge filters (3 criteria)'));
|
||||
assert.match(why, /Accuracy does: a citation that escapes the repo root, or a negative line, refutes the finding as a claim about this codebase\. A line past the end of the file does not: the citation is wrong, the claim is unchecked\./,
|
||||
'the paragraph after the table still lets a line number alone refute');
|
||||
});
|
||||
|
||||
test('[DJ] /trekreview Phase 6 passes each reviewer\'s Declined to Judge lines verbatim for the coordinator to copy', () => {
|
||||
const p6 = flat(section(read(REVIEW), '## Phase 6 — Coordinator dedup + verdict'));
|
||||
assert.match(p6, /pass each reviewer's `### Declined to Judge` lines verbatim from its saved `\{project_dir\}\/\.review-out-\{reviewer\}\.md`: the coordinator copies them into `## Declined to Judge`, so nothing a reviewer set aside disappears\./,
|
||||
'Phase 6 no longer hands the reviewers\' Declined to Judge lines to the coordinator');
|
||||
});
|
||||
|
||||
test('[DJ] review-coordinator Input: the reviewers\' Declined to Judge lines are copied into body section 9, not ruled on', () => {
|
||||
const input = flat(section(read(COORD), '## Input'));
|
||||
assert.match(input, /\*\*Reviewers' Declined to Judge lines\*\* — each reviewer's own `### Declined to Judge` list, verbatim\. You copy them into `## Declined to Judge` \(body section 9\); you do not rule on them\./,
|
||||
'the coordinator\'s Input no longer names the reviewers\' Declined to Judge lines to copy');
|
||||
});
|
||||
|
||||
test('[DJ] review-coordinator body section 9 copies every reviewer Declined to Judge line as {reviewer}: {line}, outside the JSON array and the verdict', () => {
|
||||
const body = flat(section(read(COORD), '### Body sections (in order)'));
|
||||
assert.match(body, /then every line a reviewer wrote under its own `### Declined to Judge`, copied as `\{reviewer\}: \{line\}` \(they are not findings: they stay out of the JSON `declined_to_judge` array and do not change the verdict\)/,
|
||||
'body section 9 no longer copies the reviewers\' Declined to Judge lines');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue