// tests/scripts/trekreview-armb-workflow.test.mjs // The opt-in Workflow substrate for /trekreview Phase 5–6, run for real with // stubbed Workflow globals (agent/parallel/phase/log). Ordre 5: a reviewer or // engine that did not report forbids ALLOW, and the verdict's floor is // recomputed from the findings the coordinator returns. import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { readFileSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..'); const SRC = readFileSync(join(ROOT, 'scripts', 'trekreview-armB.workflow.mjs'), 'utf-8') .replace('export const meta', 'const meta'); const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor; const run = new AsyncFunction('args', 'agent', 'parallel', 'phase', 'log', SRC); const BASE = { briefPath: 'b.md', diffPath: 'd.diff', triage: '' }; const engine = (reviewer, findings = []) => ({ reviewer, findings }); function stubs({ reviewers = [], coordinator = null } = {}) { let i = 0; return { agent: async (_prompt, opts) => (opts.label === 'coordinator' ? coordinator : reviewers[i++] ?? null), parallel: async (thunks) => Promise.all(thunks.map((t) => t())), phase: () => {}, log: () => {}, }; } async function exec(args, s) { return run(args, s.agent, s.parallel, s.phase, s.log); } test('armB — both reviewers and both engines clean → ALLOW (known-positive control)', async () => { const s = stubs({ reviewers: [{ reviewer: 'c', findings: [] }, { reviewer: 'k', findings: [] }] }); const r = await exec({ ...BASE, enginePayloads: [engine('claude-code-review'), engine('claude-security-review')] }, s); assert.equal(r.verdict, 'ALLOW'); assert.deepEqual(r.missing_engines, []); }); test('armB — engines the caller never mentioned are missing → not ALLOW', async () => { const s = stubs({ reviewers: [{ reviewer: 'c', findings: [] }, { reviewer: 'k', findings: [] }] }); const r = await exec({ ...BASE }, s); assert.equal(r.verdict, 'WARN'); assert.deepEqual(r.missing_engines, ['claude-code-review', 'claude-security-review']); }); test('armB — a reviewer that returned nothing → not ALLOW', async () => { const s = stubs({ reviewers: [null, { reviewer: 'k', findings: [] }] }); const r = await exec({ ...BASE, enginePayloads: [engine('claude-code-review'), engine('claude-security-review')] }, s); assert.equal(r.verdict, 'WARN'); }); test('armB — a coordinator ALLOW over a BLOCKER finding is recomputed to BLOCK', async () => { const f = { severity: 'BLOCKER', rule_key: 'UNIMPLEMENTED_CRITERION', file: 'a.mjs', line: 1, title: 't', detail: 'd' }; const s = stubs({ reviewers: [{ reviewer: 'c', findings: [f] }, { reviewer: 'k', findings: [] }], coordinator: { verdict: 'ALLOW', findings: [f] }, }); const r = await exec({ ...BASE, enginePayloads: [engine('claude-code-review'), engine('claude-security-review')] }, s); assert.equal(r.verdict, 'BLOCK'); }); test('armB — quick mode expects only the /code-review engine', async () => { const s = stubs({ reviewers: [{ reviewer: 'k', findings: [] }] }); const r = await exec({ ...BASE, quick: true, enginePayloads: [engine('claude-code-review')] }, s); assert.equal(r.verdict, 'ALLOW'); assert.deepEqual(r.missing_engines, []); });