Files
gstack/test/review-n-plus-one-contract.test.ts
T
garrytan 17ee2e5428 test(review-army): record N+1's pre-dispatch stages and scope the session to Step 4.5
review-army-perf-n-plus-one timed out in 7 of 13 CI runs on this branch (passing
245-280 s of 300). Each session spent ~95 s on setup (the full extracted SKILL,
checklist, section greps, exploratory.md, diff-scope/stats/learnings, tooling
checks), ran Step 4's core pass, a search-before-recommending WebSearch, and
wrote a 10-16 KB report (~100 s after the Red Team returned).

The fixture now stages only review/sections/review-army.md plus the performance
and red-team checklists, and hands the session the recorded detect-scope,
specialist-stats and learnings outputs and the diff. The caller passes
--performance (every CI parent already treated the prompt as that force flag
against the <50-line skip), declares the core pass, QA, adversarial review, web
research, Fix-First and persistence out of scope, and caps the report at the
selection line, the SPECIALIST REVIEW block and the Red Team result (30 lines).
The Performance specialist and the conditional Red Team are still real
foreground subagents, and the report still has to surface the N+1.

New assertion: a foreground Performance specialist dispatch precedes the Red
Team dispatch. Free controls omit the Performance dispatch or background it, and
both fail; the budget lifecycle adapter supplies the current result shape.
Touchfiles now include the .rb fixture the case reads.
2026-09-30 20:54:35 +00:00

63 lines
3.9 KiB
TypeScript

import {expect, test} from 'bun:test';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import {spawnSync} from 'node:child_process';
const ROOT = path.resolve(import.meta.dir, '..');
test.each(['complete-control', 'captured-omission', 'claimed-only', 'background', 'missing-report', 'unrelated-report', 'captured-timeout', 'performance-omitted', 'performance-background'])
('N+1 registered completion contract: %s', scenario => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'n1-contract-'));
const facts = path.join(dir, 'facts.json');
const script = path.join(dir, 'callback.test.ts');
fs.writeFileSync(script, `
import {describe,expect,mock,test} from 'bun:test';
import * as fs from 'node:fs';
import * as path from 'node:path';
const root=${JSON.stringify(ROOT)},scenario=${JSON.stringify(scenario)},facts=${JSON.stringify(facts)};
const actual=await import(path.join(root,'test/helpers/session-runner.ts'));
const fixture=JSON.parse(fs.readFileSync(path.join(root,'test/fixtures/review-n-plus-one-dispatch.json'),'utf8'));
const data=structuredClone(['captured-omission','claimed-only'].includes(scenario)?fixture.omission:fixture.ci);
if(scenario==='background')data.events[1].message.content[0].input.run_in_background=true;
if(scenario==='performance-background')data.events[0].message.content[0].input.run_in_background=true;
if(scenario==='performance-omitted')data.events.shift();
const parsed=actual.parseNDJSON(data.events.map(e=>JSON.stringify(e)));
let prompt='';
mock.module(path.join(root,'test/helpers/e2e-helpers.ts'),()=>({
ROOT:root,runId:'n1-contract',
describeIfSelected:(name,ids,body)=>{if(ids.includes('review-army-perf-n-plus-one'))describe(name,body);},
testConcurrentIfSelected:(id,body,timeout)=>{if(id==='review-army-perf-n-plus-one')test(id,body,timeout);},
logCost(){},createEvalCollector:()=>null,finalizeEvalCollector:async()=>{},
recordE2E:(_collector,_name,_suite,result,extra)=>fs.writeFileSync(facts,JSON.stringify({
passed:extra?.passed??result.exitReason==='success',exitReason:result.exitReason,toolCalls:result.toolCalls,prompt,
})),
}));
mock.module(path.join(root,'test/helpers/session-runner.ts'),()=>({...actual,runSkillTest:async options=>{
expect(options.timeout).toBe(300000);expect(options.maxTurns).toBe(20);
prompt=options.prompt;
if(scenario!=='missing-report')fs.writeFileSync(path.join(options.workingDirectory,'review-output.md'),
scenario==='unrelated-report'?'No relevant evidence':'N+1 queries at posts_controller.rb:7 and :9.'+
(scenario==='claimed-only'?' Red Team completed.':''));
return {exitReason:scenario==='captured-timeout'?'timeout':'success',browseErrors:[],toolCalls:parsed.toolCalls,
transcript:parsed.transcript,output:data.publicAcknowledgement??'Synthetic successful completion control.'};
}}));
await import(path.join(root,'test/skill-e2e-review-army.test.ts'));
`);
try {
const child = spawnSync(process.execPath, ['test', script], {
cwd: dir, encoding: 'utf8', timeout: 10_000,
env: {PATH: process.env.PATH ?? '', HOME: dir, TMPDIR: dir, NO_COLOR: '1'},
});
expect(child.status, child.stdout + child.stderr).toBe(scenario === 'complete-control' ? 0 : 1);
expect(child.stderr).not.toContain('Unhandled error between tests');
expect(fs.existsSync(facts), child.stdout + child.stderr).toBe(true);
const observed = JSON.parse(fs.readFileSync(facts, 'utf8'));
expect(observed.passed).toBe(scenario === 'complete-control');
expect(observed.exitReason).toBe(scenario === 'captured-timeout' ? 'timeout' : 'success');
expect(observed.prompt).toContain('conditional Red Team dispatch');
expect(observed.prompt).toContain('separate foreground Red Team subagent');
expect(observed.prompt).toContain('brief acknowledgement');
} finally {
fs.rmSync(dir, {recursive: true, force: true});
}
});