fix(review): the workflow review floors an illegally lowered brief-conflict finding

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-12 18:16:07 +02:00
commit 8cc6ba0181
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
2 changed files with 331 additions and 5 deletions

View file

@ -9,6 +9,8 @@ import { strict as assert } from 'node:assert';
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { illegalBriefLowering } from '../../lib/review/coordinator-contract.mjs';
import { RULE_CATALOGUE } from '../../lib/review/rule-catalogue.mjs';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const SRC = readFileSync(join(ROOT, 'scripts', 'trekreview-armB.workflow.mjs'), 'utf-8')
@ -21,8 +23,17 @@ const engine = (reviewer, findings = []) => ({ reviewer, findings });
function stubs({ reviewers = [], coordinator = null } = {}) {
let i = 0;
const calls = { coordinatorPrompt: null, coordinatorOpts: null };
return {
agent: async (_prompt, opts) => (opts.label === 'coordinator' ? coordinator : reviewers[i++] ?? null),
calls,
agent: async (prompt, opts) => {
if (opts.label === 'coordinator') {
calls.coordinatorPrompt = prompt;
calls.coordinatorOpts = opts;
return coordinator;
}
return reviewers[i++] ?? null;
},
parallel: async (thunks) => Promise.all(thunks.map((t) => t())),
phase: () => {},
log: () => {},
@ -69,3 +80,244 @@ test('armB — quick mode expects only the /code-review engine', async () => {
assert.equal(r.verdict, 'ALLOW');
assert.deepEqual(r.missing_engines, []);
});
// ---- Step 9: the brief-conflict rule on the Workflow path ---------------------------
//
// Each case stubs the reviewers' and engines' payloads (so `merged` holds the
// input), the coordinator's returned findings and its verdict, then asserts the
// workflow's verdict. `merged` is read from the prompt the coordinator stub
// receives. For every case the test states the value of `illegalBriefLowering`
// on the subject finding as returned, with `engine` set from its counterpart's
// source (removed when the counterpart is a reviewer finding or absent), and
// checks the floor raised a finding exactly where that value is true — plus
// case 7, where a false `engine` label alone raises.
const RANK = ['BLOCKER', 'MAJOR', 'MINOR', 'SUGGESTION'];
const rank = (s) => (RANK.indexOf(s) === -1 ? RANK.length : RANK.indexOf(s));
const MARK = 'Non-Goal: no new runtime dependency';
const FILE = 'src/a.mjs';
const LINE = 10;
const F = (rule_key, severity, extra = {}) => ({ severity, rule_key, file: FILE, line: LINE, title: 't', detail: 'd', ...extra });
const PROMPT_JSON_MARK = '=== PRE-DEDUPED FINDINGS (JSON) ===';
const triplet = (f) => `${f.file}\u0000${f.line}\u0000${f.rule_key}`;
async function floorCase({ reviewerFindings = [], codeFindings = [], securityFindings = [], quick = false, returned, verdict }) {
const before = structuredClone(returned);
const coordinator = { verdict, findings: structuredClone(returned) };
const reviewers = quick
? [{ reviewer: 'code-correctness', findings: structuredClone(reviewerFindings) }]
: [{ reviewer: 'brief-conformance', findings: structuredClone(reviewerFindings) }, { reviewer: 'code-correctness', findings: [] }];
const enginePayloads = quick
? [engine('claude-code-review', structuredClone(codeFindings))]
: [engine('claude-code-review', structuredClone(codeFindings)), engine('claude-security-review', structuredClone(securityFindings))];
const s = stubs({ reviewers, coordinator });
const r = await exec({ ...BASE, quick, enginePayloads }, s);
const prompt = s.calls.coordinatorPrompt;
assert.ok(typeof prompt === 'string', 'the coordinator ran');
const merged = JSON.parse(prompt.slice(prompt.indexOf(PROMPT_JSON_MARK) + PROMPT_JSON_MARK.length));
const raised = r.findings.some((f, i) => rank(f.severity) < rank(before[i].severity));
return { r, merged, before, raised, s };
}
// The subject (index 0 of `returned`) with `engine` from its counterpart's source.
function subjectIllegal(before, merged, idx = 0) {
const subject = { ...before[idx] };
const counterpart = merged.find((m) => triplet(m) === triplet(subject));
if (counterpart && counterpart.engine) subject.engine = counterpart.engine;
else delete subject.engine;
return illegalBriefLowering(subject);
}
function checkRaise({ before, merged, raised }, statedIllegal, extraRaise = false) {
assert.equal(subjectIllegal(before, merged), statedIllegal, 'illegalBriefLowering on the subject');
assert.equal(raised, statedIllegal || extraRaise, 'the floor raised a finding exactly where the shape is illegal');
}
test('armB brief rule (1) — an unlabelled SECURITY_REVIEW_VULNERABILITY returned at MINOR over a /security-review BLOCKER → BLOCK', async () => {
const c = await floorCase({
securityFindings: [F('SECURITY_REVIEW_VULNERABILITY', 'BLOCKER')],
returned: [F('SECURITY_REVIEW_VULNERABILITY', 'MINOR')],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'BLOCK');
assert.equal(c.r.findings[0].engine, 'security-review');
checkRaise(c, true);
});
test('armB brief rule (2) — an unlabelled CODE_REVIEW_DEFECT returned at MINOR over a /code-review MAJOR with ALLOW → WARN', async () => {
const c = await floorCase({
codeFindings: [F('CODE_REVIEW_DEFECT', 'MAJOR')],
returned: [F('CODE_REVIEW_DEFECT', 'MINOR')],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'WARN');
checkRaise(c, true);
});
for (const withEngine of [true, false]) {
test(`armB brief rule (3) — the legal lowering keeps ALLOW (returned ${withEngine ? 'with' : 'without'} engine) and carries engine code-review`, async () => {
const lowered = F('CODE_REVIEW_DEFECT', 'MINOR', { contradicts_brief: MARK, brief_lowered_from: 'MAJOR' });
if (withEngine) lowered.engine = 'code-review';
const c = await floorCase({
codeFindings: [F('CODE_REVIEW_DEFECT', 'MAJOR')],
returned: [lowered],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'ALLOW');
assert.equal(c.r.findings[0].engine, 'code-review');
assert.equal(c.r.findings[0].severity, 'MINOR');
checkRaise(c, false);
});
}
test('armB brief rule (4) — the legal shape over a reviewer CODE_REVIEW_DEFECT asserted BLOCKER (relabelled engine) → BLOCK, no engine', async () => {
const c = await floorCase({
reviewerFindings: [F('CODE_REVIEW_DEFECT', 'BLOCKER')],
returned: [F('CODE_REVIEW_DEFECT', 'MINOR', { engine: 'code-review', contradicts_brief: MARK, brief_lowered_from: 'MAJOR' })],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'BLOCK');
assert.equal(c.r.findings[0].engine, undefined);
checkRaise(c, true);
});
test('armB brief rule (5) — a reviewer finding that carries engine code-review is not an engine finding: the source decides → WARN', async () => {
const c = await floorCase({
reviewerFindings: [F('CODE_REVIEW_DEFECT', 'MAJOR', { engine: 'code-review' })],
returned: [F('CODE_REVIEW_DEFECT', 'MINOR', { engine: 'code-review', contradicts_brief: MARK, brief_lowered_from: 'MAJOR' })],
verdict: 'ALLOW',
});
assert.equal(c.merged[0].engine, undefined, 'a reviewer engine field never reaches merged');
assert.equal(c.r.verdict, 'WARN');
checkRaise(c, true);
});
test('armB brief rule (6) — a marked reviewer MISSING_TEST asserted BLOCKER, returned at MAJOR with WARN → BLOCK', async () => {
const c = await floorCase({
reviewerFindings: [F('MISSING_TEST', 'BLOCKER')],
returned: [F('MISSING_TEST', 'MAJOR', { contradicts_brief: MARK })],
verdict: 'WARN',
});
assert.equal(c.r.verdict, 'BLOCK');
checkRaise(c, true);
});
test('armB brief rule (7) — a reviewer MISSING_TEST asserted BLOCKER, returned at MAJOR with only engine security-review → BLOCK, no engine', async () => {
const c = await floorCase({
reviewerFindings: [F('MISSING_TEST', 'BLOCKER')],
returned: [F('MISSING_TEST', 'MAJOR', { engine: 'security-review' })],
verdict: 'WARN',
});
assert.equal(c.r.verdict, 'BLOCK');
assert.equal(c.r.findings[0].engine, undefined);
checkRaise(c, false, true);
});
test('armB brief rule (8) — a stray brief_lowered_from on a reviewer finding asserted BLOCKER, returned at MAJOR with WARN → BLOCK', async () => {
const c = await floorCase({
reviewerFindings: [F('MISSING_TEST', 'BLOCKER')],
returned: [F('MISSING_TEST', 'MAJOR', { brief_lowered_from: 'MAJOR' })],
verdict: 'WARN',
});
assert.equal(c.r.verdict, 'BLOCK');
checkRaise(c, true);
});
test('armB brief rule (9) — a marked finding with no counterpart and an unknown rule_key, returned at MINOR with ALLOW → BLOCK', async () => {
const other = { severity: 'MINOR', rule_key: 'MISSING_ERROR_HANDLING', file: 'src/b.mjs', line: 3, title: 't', detail: 'd' };
const c = await floorCase({
reviewerFindings: [other],
returned: [{ severity: 'MINOR', rule_key: 'NOT_IN_THE_CATALOGUE', file: 'src/ghost.mjs', line: 7, title: 't', detail: 'd', contradicts_brief: MARK }, other],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'BLOCK');
checkRaise(c, true);
});
test('armB brief rule (10) — a marked BLOCKER-tier /code-review finding returned at MINOR → BLOCK', async () => {
const c = await floorCase({
codeFindings: [F('SECURITY_INJECTION', 'BLOCKER')],
returned: [F('SECURITY_INJECTION', 'MINOR', { engine: 'code-review', contradicts_brief: MARK })],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'BLOCK');
checkRaise(c, true);
});
test('armB brief rule (11) — dedup keeps the /code-review MAJOR over a first-seen reviewer MINOR on the same triplet → WARN', async () => {
const c = await floorCase({
reviewerFindings: [F('CODE_REVIEW_DEFECT', 'MINOR')],
codeFindings: [F('CODE_REVIEW_DEFECT', 'MAJOR')],
returned: [F('CODE_REVIEW_DEFECT', 'MINOR')],
verdict: 'ALLOW',
});
assert.equal(c.merged.length, 1);
assert.equal(c.merged[0].severity, 'MAJOR');
assert.equal(c.merged[0].engine, 'code-review');
assert.equal(c.r.deduped_count, 1);
assert.equal(c.r.raw_finding_count, 2);
assert.equal(c.r.verdict, 'WARN');
checkRaise(c, true);
});
test('armB brief rule (12) — an unlabelled reviewer MISSING_TEST asserted BLOCKER, returned at MAJOR (catalogue reset) with WARN stays WARN', async () => {
const c = await floorCase({
reviewerFindings: [F('MISSING_TEST', 'BLOCKER')],
returned: [F('MISSING_TEST', 'MAJOR')],
verdict: 'WARN',
});
assert.equal(c.r.verdict, 'WARN');
checkRaise(c, false);
});
test('armB brief rule (13) — a marked MINOR-tier engine finding at its tier (CODE_REVIEW_IMPROVEMENT) keeps ALLOW', async () => {
const c = await floorCase({
codeFindings: [F('CODE_REVIEW_IMPROVEMENT', 'MINOR')],
returned: [F('CODE_REVIEW_IMPROVEMENT', 'MINOR', { engine: 'code-review', contradicts_brief: MARK })],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'ALLOW');
assert.equal(c.r.findings[0].engine, 'code-review');
checkRaise(c, false);
});
test('armB brief rule (14) — an unlabelled reviewer MISSING_TEST at MINOR (quick mode) keeps the coordinator verdict', async () => {
const c = await floorCase({
quick: true,
reviewerFindings: [F('MISSING_TEST', 'MINOR')],
returned: [F('MISSING_TEST', 'MINOR')],
verdict: 'ALLOW',
});
assert.equal(c.r.verdict, 'ALLOW');
checkRaise(c, false);
});
test('armB brief rule — RULE_TIERS in the script equals the catalogue (same keys, same tiers)', () => {
const start = SRC.indexOf('const RULE_TIERS = {');
assert.ok(start !== -1, 'the script carries a RULE_TIERS literal block');
const block = SRC.slice(start, SRC.indexOf('};', start));
const tiers = Object.fromEntries([...block.matchAll(/([A-Z_]+):\s*'([A-Z]+)'/g)].map((m) => [m[1], m[2]]));
const catalogue = Object.fromEntries(RULE_CATALOGUE.map((r) => [r.rule_key, r.severity]));
assert.deepEqual(tiers, catalogue);
});
test('armB brief rule — VERDICT_SCHEMA declares engine, contradicts_brief and brief_lowered_from; the prompt states the rule', async () => {
const c = await floorCase({
codeFindings: [F('CODE_REVIEW_DEFECT', 'MAJOR')],
returned: [F('CODE_REVIEW_DEFECT', 'MAJOR')],
verdict: 'WARN',
});
const props = c.s.calls.coordinatorOpts.schema.properties.findings.items.properties;
assert.deepEqual(props.engine, { type: 'string', enum: ['code-review', 'security-review'] });
assert.deepEqual(props.contradicts_brief, { type: 'string' });
assert.deepEqual(props.brief_lowered_from, { type: 'string', enum: ['MAJOR'] });
const prompt = c.s.calls.coordinatorPrompt;
assert.ok(prompt.includes('contradicts_brief'));
assert.ok(prompt.includes('brief_lowered_from'));
assert.ok(prompt.includes('## Non-Goals'));
assert.ok(prompt.includes('## Constraints'));
assert.ok(prompt.includes('## Preferences'));
assert.ok(prompt.includes('## Open Questions / Assumptions'));
assert.ok(/only an engine finding/i.test(prompt), 'engine findings only');
assert.ok(/kept and marked, never removed/i.test(prompt));
});