Files
waggle-os/packages/agent/tests/long-task-report.test.ts
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

507 lines
27 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Tests for long-task/report.ts (Phase 4.2 of agent-fix sprint).
*
* Coverage:
* - Report shape: summary.json schema, predictions.jsonl, failures.jsonl, summary.md
* - Per-cell metrics correctness (accuracy raw/normalized, abstention, leakage, etc.)
* - Wilson 95% CI: math correctness, edge cases (n=0, p=0, p=1)
* - Bootstrap CI: triggers iff n >= 30, deterministic via seeded RNG
* - Cross-model matrix: rows × columns shape, NaN for missing cells
* - Best-per-cell argmax + ties handling
* - Win/loss vs baseline (pp delta)
* - Regression notes (5pp drop threshold)
* - Aggregate failure distribution
* - Markdown rendering: known-shape sections present
* - writeReportToDisk: 4 files written
* - Pilot adapter: fromPilotRecord shape mapping
* - End-to-end pilot reproduction: smoke-records.jsonl (N=20) reproduces D3 finding (40% substring)
*/
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import * as fsp from 'node:fs/promises';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
import {
generateReport,
writeReportToDisk,
fromPilotRecord,
type AgentPredictionRecord,
type ReportOptions,
type PilotJsonlRecord,
} from '../src/long-task/report.js';
// ─────────────────────────────────────────────────────────────────────────
// Fixtures
// ─────────────────────────────────────────────────────────────────────────
let tmpRoot: string;
beforeEach(async () => {
tmpRoot = await fsp.mkdtemp(path.join(os.tmpdir(), 'waggle-report-'));
});
afterEach(async () => {
await fsp.rm(tmpRoot, { recursive: true, force: true });
});
function rec(overrides: Partial<AgentPredictionRecord> & { model: string; cell: string }): AgentPredictionRecord {
return {
instance_id: 'inst-1',
gold_answer: 'gold',
output_raw: 'output',
output_normalized: 'output',
...overrides,
};
}
const baseOpts: ReportOptions = { run_id: 'test-run' };
// ─────────────────────────────────────────────────────────────────────────
// Empty / trivial reports
// ─────────────────────────────────────────────────────────────────────────
describe('report — empty / trivial', () => {
it('handles empty record list', async () => {
const r = await generateReport([], baseOpts);
expect(r.summary.n_instances).toBe(0);
expect(r.summary.models).toEqual([]);
expect(r.summary.cells).toEqual([]);
expect(r.predictions_jsonl).toBe('');
expect(r.failures_jsonl).toBe('');
});
it('handles single-record perfect case', async () => {
const records = [rec({ model: 'm1', cell: 'raw', output_raw: 'gold', output_normalized: 'gold' })];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m1?.raw?.accuracy_normalized).toBe(1);
expect(r.summary.per_model_per_cell.m1?.raw?.accuracy_raw).toBe(1);
});
it('handles single-record failure case', async () => {
const records = [rec({ model: 'm1', cell: 'raw', output_raw: 'wrong', output_normalized: 'wrong' })];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m1?.raw?.accuracy_normalized).toBe(0);
expect(r.failures_jsonl.split('\n').length).toBe(1);
});
});
// ─────────────────────────────────────────────────────────────────────────
// Wilson CI math
// ─────────────────────────────────────────────────────────────────────────
describe('report — Wilson CI math', () => {
it('Wilson: 5/10 → CI roughly [0.24, 0.76]', async () => {
const records = Array.from({ length: 10 }, (_, i) =>
rec({ model: 'm', cell: 'c', output_normalized: i < 5 ? 'gold' : 'wrong', instance_id: `i-${i}` }));
const r = await generateReport(records, baseOpts);
const m = r.summary.per_model_per_cell.m!.c!;
expect(m.accuracy_normalized).toBe(0.5);
expect(m.wilson_95ci_lower).toBeGreaterThan(0.20);
expect(m.wilson_95ci_lower).toBeLessThan(0.30);
expect(m.wilson_95ci_upper).toBeGreaterThan(0.70);
expect(m.wilson_95ci_upper).toBeLessThan(0.80);
});
it('Wilson: 0/10 → lower bound = 0', async () => {
const records = Array.from({ length: 10 }, (_, i) =>
rec({ model: 'm', cell: 'c', output_normalized: 'wrong', instance_id: `i-${i}` }));
const r = await generateReport(records, baseOpts);
const m = r.summary.per_model_per_cell.m!.c!;
expect(m.wilson_95ci_lower).toBe(0);
});
it('Wilson: 10/10 → upper bound = 1 (within FP precision)', async () => {
const records = Array.from({ length: 10 }, (_, i) =>
rec({ model: 'm', cell: 'c', output_normalized: 'gold', instance_id: `i-${i}` }));
const r = await generateReport(records, baseOpts);
const m = r.summary.per_model_per_cell.m!.c!;
expect(m.wilson_95ci_upper).toBeCloseTo(1, 10);
});
it('Wilson half_width is in pp (×100)', async () => {
const records = Array.from({ length: 100 }, (_, i) =>
rec({ model: 'm', cell: 'c', output_normalized: i < 50 ? 'gold' : 'wrong', instance_id: `i-${i}` }));
const r = await generateReport(records, baseOpts);
const m = r.summary.per_model_per_cell.m!.c!;
// At p=0.5, n=100: half-width ≈ 9.8 pp
expect(m.wilson_95ci_half_width_pp).toBeGreaterThan(8);
expect(m.wilson_95ci_half_width_pp).toBeLessThan(12);
});
});
// ─────────────────────────────────────────────────────────────────────────
// Bootstrap CI gating + determinism
// ─────────────────────────────────────────────────────────────────────────
describe('report — Bootstrap CI', () => {
it('does NOT compute bootstrap when N < 30', async () => {
const records = Array.from({ length: 20 }, (_, i) =>
rec({ model: 'm', cell: 'c', output_normalized: i < 10 ? 'gold' : 'wrong', instance_id: `i-${i}` }));
const r = await generateReport(records, baseOpts);
const m = r.summary.per_model_per_cell.m!.c!;
expect(m.bootstrap_95ci_lower).toBeUndefined();
expect(m.bootstrap_95ci_upper).toBeUndefined();
});
it('DOES compute bootstrap when N >= 30', async () => {
const records = Array.from({ length: 30 }, (_, i) =>
rec({ model: 'm', cell: 'c', output_normalized: i < 15 ? 'gold' : 'wrong', instance_id: `i-${i}` }));
const r = await generateReport(records, baseOpts);
const m = r.summary.per_model_per_cell.m!.c!;
expect(m.bootstrap_95ci_lower).toBeGreaterThan(0);
expect(m.bootstrap_95ci_upper).toBeLessThan(1);
});
it('seeded rng → deterministic bootstrap output', async () => {
let seed = 1;
const seededRng = () => { seed = (seed * 1664525 + 1013904223) >>> 0; return seed / 4294967296; };
const records = Array.from({ length: 50 }, (_, i) =>
rec({ model: 'm', cell: 'c', output_normalized: i < 25 ? 'gold' : 'wrong', instance_id: `i-${i}` }));
seed = 1;
const r1 = await generateReport(records, { ...baseOpts, rng: seededRng, bootstrap_iterations: 200 });
seed = 1;
const r2 = await generateReport(records, { ...baseOpts, rng: seededRng, bootstrap_iterations: 200 });
expect(r1.summary.per_model_per_cell.m!.c!.bootstrap_95ci_lower).toBe(r2.summary.per_model_per_cell.m!.c!.bootstrap_95ci_lower);
});
});
// ─────────────────────────────────────────────────────────────────────────
// Per-cell metric correctness
// ─────────────────────────────────────────────────────────────────────────
describe('report — per-cell metrics', () => {
it('abstention rate counts unknown-class outputs', async () => {
const records = [
rec({ model: 'm', cell: 'c', output_normalized: 'unknown', instance_id: 'i1' }),
rec({ model: 'm', cell: 'c', output_normalized: 'I don\'t know', instance_id: 'i2' }),
rec({ model: 'm', cell: 'c', output_normalized: 'gold', instance_id: 'i3' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m!.c!.abstention_rate).toBeCloseTo(2 / 3);
});
it('thinking_leakage rate counts <think> in raw output', async () => {
const records = [
rec({ model: 'm', cell: 'c', output_raw: '<think>x</think>gold', output_normalized: 'gold', instance_id: 'i1' }),
rec({ model: 'm', cell: 'c', output_raw: 'gold', output_normalized: 'gold', instance_id: 'i2' }),
rec({ model: 'm', cell: 'c', output_raw: '<THINKING>y</THINKING>gold', output_normalized: 'gold', instance_id: 'i3' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m!.c!.thinking_leakage_rate).toBeCloseTo(2 / 3);
});
it('avg output chars: raw + normalized separately', async () => {
const records = [
rec({ model: 'm', cell: 'c', output_raw: 'aaaa', output_normalized: 'aa', instance_id: 'i1' }),
rec({ model: 'm', cell: 'c', output_raw: 'bbbbbb', output_normalized: 'bbb', instance_id: 'i2' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m!.c!.avg_output_chars_raw).toBe(5);
expect(r.summary.per_model_per_cell.m!.c!.avg_output_chars_normalized).toBe(2.5);
});
it('total cost sums per cell', async () => {
const records = [
rec({ model: 'm', cell: 'c', cost_usd: 0.01, instance_id: 'i1' }),
rec({ model: 'm', cell: 'c', cost_usd: 0.02, instance_id: 'i2' }),
rec({ model: 'm', cell: 'c', cost_usd: 0.03, instance_id: 'i3' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m!.c!.total_cost_usd).toBeCloseTo(0.06);
});
it('avg latency per cell', async () => {
const records = [
rec({ model: 'm', cell: 'c', latency_ms: 100, instance_id: 'i1' }),
rec({ model: 'm', cell: 'c', latency_ms: 200, instance_id: 'i2' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m!.c!.avg_latency_ms).toBe(150);
});
it('failure_distribution buckets failures by Phase 4.1 category', async () => {
const records = [
// thinking_leakage
rec({ model: 'm', cell: 'c', output_raw: '<think>x</think>wrong', output_normalized: '<think>x</think>wrong', instance_id: 'i1' }),
// unknown_false_negative
rec({ model: 'm', cell: 'c', output_normalized: 'unknown', instance_id: 'i2' }),
// correct (not a failure)
rec({ model: 'm', cell: 'c', output_normalized: 'gold', instance_id: 'i3' }),
];
const r = await generateReport(records, baseOpts);
const dist = r.summary.per_model_per_cell.m!.c!.failure_distribution;
expect(dist.thinking_leakage).toBe(1);
expect(dist.unknown_false_negative).toBe(1);
});
});
// ─────────────────────────────────────────────────────────────────────────
// Cross-model matrix + best-per-cell + win/loss
// ─────────────────────────────────────────────────────────────────────────
describe('report — cross-model + win/loss', () => {
it('matrix has cells × models shape with sorted axes', async () => {
const records = [
rec({ model: 'qwen', cell: 'raw', output_normalized: 'gold', instance_id: 'i1' }),
rec({ model: 'opus', cell: 'raw', output_normalized: 'wrong', instance_id: 'i2' }),
rec({ model: 'qwen', cell: 'compressed', output_normalized: 'gold', instance_id: 'i3' }),
rec({ model: 'opus', cell: 'compressed', output_normalized: 'gold', instance_id: 'i4' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.cross_model_matrix.rows).toEqual(['compressed', 'raw']);
expect(r.summary.cross_model_matrix.columns).toEqual(['opus', 'qwen']);
// (compressed, opus) = 1, (compressed, qwen) = 1, (raw, opus) = 0, (raw, qwen) = 1
expect(r.summary.cross_model_matrix.values[0]).toEqual([1, 1]);
expect(r.summary.cross_model_matrix.values[1]).toEqual([0, 1]);
});
it('NaN for missing (model, cell) combinations', async () => {
const records = [
rec({ model: 'qwen', cell: 'raw', output_normalized: 'gold', instance_id: 'i1' }),
rec({ model: 'opus', cell: 'compressed', output_normalized: 'gold', instance_id: 'i2' }),
];
const r = await generateReport(records, baseOpts);
// (compressed, opus) = 1, (compressed, qwen) = NaN
// (raw, opus) = NaN, (raw, qwen) = 1
expect(Number.isNaN(r.summary.cross_model_matrix.values[0]![1]!)).toBe(true);
expect(Number.isNaN(r.summary.cross_model_matrix.values[1]![0]!)).toBe(true);
});
it('best_per_cell picks argmax model', async () => {
const records = [
rec({ model: 'qwen', cell: 'raw', output_normalized: 'gold', instance_id: 'i1' }),
rec({ model: 'qwen', cell: 'raw', output_normalized: 'wrong', instance_id: 'i2' }),
rec({ model: 'opus', cell: 'raw', output_normalized: 'gold', instance_id: 'i3' }),
rec({ model: 'opus', cell: 'raw', output_normalized: 'gold', instance_id: 'i4' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.best_per_cell.raw).toBe('opus');
});
it('win_loss_vs_baseline_pp computed for non-baseline cells', async () => {
const records = [
// m1/raw: 1/2 = 50%
rec({ model: 'm1', cell: 'raw', output_normalized: 'gold', instance_id: 'i1' }),
rec({ model: 'm1', cell: 'raw', output_normalized: 'wrong', instance_id: 'i2' }),
// m1/compressed: 2/2 = 100%
rec({ model: 'm1', cell: 'compressed', output_normalized: 'gold', instance_id: 'i3' }),
rec({ model: 'm1', cell: 'compressed', output_normalized: 'gold', instance_id: 'i4' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.per_model_per_cell.m1!.compressed!.win_loss_vs_baseline_pp).toBeCloseTo(50);
// baseline cell itself has no win/loss
expect(r.summary.per_model_per_cell.m1!.raw!.win_loss_vs_baseline_pp).toBeUndefined();
});
it('custom baseline_cell honored', async () => {
const records = [
rec({ model: 'm1', cell: 'compressed', output_normalized: 'gold', instance_id: 'i1' }),
rec({ model: 'm1', cell: 'raw', output_normalized: 'gold', instance_id: 'i2' }),
];
const r = await generateReport(records, { ...baseOpts, baseline_cell: 'compressed' });
expect(r.summary.baseline_cell).toBe('compressed');
expect(r.summary.per_model_per_cell.m1!.compressed!.win_loss_vs_baseline_pp).toBeUndefined();
expect(r.summary.per_model_per_cell.m1!.raw!.win_loss_vs_baseline_pp).toBeCloseTo(0);
});
});
// ─────────────────────────────────────────────────────────────────────────
// Regression notes
// ─────────────────────────────────────────────────────────────────────────
describe('report — regression notes', () => {
it('flags cells with ≥ threshold_pp drop vs baseline', async () => {
// m1/raw = 90%, m1/compressed = 60% → 30pp drop, well over 5pp threshold.
const records: AgentPredictionRecord[] = [];
for (let i = 0; i < 10; i += 1) {
records.push(rec({ model: 'm1', cell: 'raw', output_normalized: i < 9 ? 'gold' : 'wrong', instance_id: `r-${i}` }));
records.push(rec({ model: 'm1', cell: 'compressed', output_normalized: i < 6 ? 'gold' : 'wrong', instance_id: `c-${i}` }));
}
const r = await generateReport(records, baseOpts);
expect(r.summary.regression_notes.length).toBe(1);
expect(r.summary.regression_notes[0]).toContain('m1/compressed');
expect(r.summary.regression_notes[0]).toContain('30.0pp');
});
it('respects custom regression_threshold_pp', async () => {
const records: AgentPredictionRecord[] = [];
for (let i = 0; i < 10; i += 1) {
records.push(rec({ model: 'm', cell: 'raw', output_normalized: 'gold', instance_id: `r-${i}` }));
records.push(rec({ model: 'm', cell: 'compressed', output_normalized: i < 8 ? 'gold' : 'wrong', instance_id: `c-${i}` }));
}
// 100% → 80% = 20pp drop
const r1 = await generateReport(records, { ...baseOpts, regression_threshold_pp: 25 });
expect(r1.summary.regression_notes.length).toBe(0); // 20 < 25
const r2 = await generateReport(records, { ...baseOpts, regression_threshold_pp: 15 });
expect(r2.summary.regression_notes.length).toBe(1); // 20 >= 15
});
it('improvements (positive delta) do NOT trigger regression notes', async () => {
const records: AgentPredictionRecord[] = [];
for (let i = 0; i < 10; i += 1) {
records.push(rec({ model: 'm', cell: 'raw', output_normalized: i < 5 ? 'gold' : 'wrong', instance_id: `r-${i}` }));
records.push(rec({ model: 'm', cell: 'compressed', output_normalized: 'gold', instance_id: `c-${i}` }));
}
const r = await generateReport(records, baseOpts);
expect(r.summary.regression_notes.length).toBe(0);
});
});
// ─────────────────────────────────────────────────────────────────────────
// Aggregate failure distribution
// ─────────────────────────────────────────────────────────────────────────
describe('report — aggregate failure distribution', () => {
it('sums across all (model, cell)', async () => {
const records = [
rec({ model: 'm1', cell: 'raw', output_raw: '<think>x</think>x', output_normalized: '<think>x</think>x', instance_id: 'i1' }),
rec({ model: 'm2', cell: 'raw', output_raw: '<think>y</think>y', output_normalized: '<think>y</think>y', instance_id: 'i2' }),
rec({ model: 'm1', cell: 'compressed', output_normalized: 'unknown', instance_id: 'i3' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary.aggregate_failure_distribution.thinking_leakage).toBe(2);
expect(r.summary.aggregate_failure_distribution.unknown_false_negative).toBe(1);
});
});
// ─────────────────────────────────────────────────────────────────────────
// Markdown rendering
// ─────────────────────────────────────────────────────────────────────────
describe('report — markdown rendering', () => {
it('contains all required sections', async () => {
const records = [
rec({ model: 'm', cell: 'raw', output_normalized: 'gold', instance_id: 'i1' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary_md).toContain('# Run Report');
expect(r.summary_md).toContain('## m');
expect(r.summary_md).toContain('## Cross-model comparison');
expect(r.summary_md).toContain('## Aggregate failure distribution');
expect(r.summary_md).toContain('## Regression notes');
});
it('uses bold for best model in cross-model table', async () => {
const records = [
rec({ model: 'qwen', cell: 'raw', output_normalized: 'wrong', instance_id: 'i1' }),
rec({ model: 'opus', cell: 'raw', output_normalized: 'gold', instance_id: 'i2' }),
];
const r = await generateReport(records, baseOpts);
expect(r.summary_md).toContain('**opus**');
});
it('shows accuracy as percent with 1 decimal', async () => {
const records = Array.from({ length: 100 }, (_, i) =>
rec({ model: 'm', cell: 'raw', output_normalized: i < 33 ? 'gold' : 'wrong', instance_id: `i-${i}` }));
const r = await generateReport(records, baseOpts);
expect(r.summary_md).toContain('33.0%');
});
});
// ─────────────────────────────────────────────────────────────────────────
// writeReportToDisk
// ─────────────────────────────────────────────────────────────────────────
describe('report — writeReportToDisk', () => {
it('writes 4 files in outputDir', async () => {
const records = [rec({ model: 'm', cell: 'raw', output_normalized: 'wrong', instance_id: 'i1' })];
const paths = await writeReportToDisk(records, { ...baseOpts, outputDir: tmpRoot });
expect(fs.existsSync(paths.summary_json_path)).toBe(true);
expect(fs.existsSync(paths.summary_md_path)).toBe(true);
expect(fs.existsSync(paths.predictions_jsonl_path)).toBe(true);
expect(fs.existsSync(paths.failures_jsonl_path)).toBe(true);
});
it('summary.json round-trips through JSON.parse', async () => {
const records = [rec({ model: 'm', cell: 'raw', output_normalized: 'wrong', instance_id: 'i1' })];
const paths = await writeReportToDisk(records, { ...baseOpts, outputDir: tmpRoot });
const parsed = JSON.parse(await fsp.readFile(paths.summary_json_path, 'utf-8'));
expect(parsed.run_id).toBe('test-run');
expect(parsed.report_version).toBe(1);
});
it('predictions.jsonl has one line per record + trailing newline', async () => {
const records = [
rec({ model: 'm', cell: 'raw', output_normalized: 'gold', instance_id: 'i1' }),
rec({ model: 'm', cell: 'raw', output_normalized: 'wrong', instance_id: 'i2' }),
];
const paths = await writeReportToDisk(records, { ...baseOpts, outputDir: tmpRoot });
const contents = await fsp.readFile(paths.predictions_jsonl_path, 'utf-8');
expect(contents.trim().split('\n').length).toBe(2);
expect(contents.endsWith('\n')).toBe(true);
});
it('failures.jsonl only contains failed instances', async () => {
const records = [
rec({ model: 'm', cell: 'raw', output_normalized: 'gold', instance_id: 'i1' }), // pass
rec({ model: 'm', cell: 'raw', output_normalized: 'wrong', instance_id: 'i2' }), // fail
];
const paths = await writeReportToDisk(records, { ...baseOpts, outputDir: tmpRoot });
const failContents = (await fsp.readFile(paths.failures_jsonl_path, 'utf-8')).trim();
expect(failContents.split('\n').length).toBe(1);
});
});
// ─────────────────────────────────────────────────────────────────────────
// fromPilotRecord adapter
// ─────────────────────────────────────────────────────────────────────────
describe('report — fromPilotRecord adapter', () => {
it('maps pilot record fields to AgentPredictionRecord', () => {
const pilot: PilotJsonlRecord = {
instance_id: 'locomo_conv-49_q089',
question: 'What habit?',
gold_answer: 'consuming soda and candy',
subject: { content: 'Consuming soda and candy.', in: 102, out: 865, cost: 0.0021, latency_ms: 7536, error: null },
trio: { majority: 'correct' },
self_judge: { verdict: 'Yes' },
};
const r = fromPilotRecord(pilot, { model: 'qwen3.6', cell: 'oracle' });
expect(r.model).toBe('qwen3.6');
expect(r.cell).toBe('oracle');
expect(r.instance_id).toBe('locomo_conv-49_q089');
expect(r.gold_answer).toBe('consuming soda and candy');
expect(r.output_raw).toBe('Consuming soda and candy.');
expect(r.output_normalized).toBe('Consuming soda and candy.');
expect(r.judge_verdict).toBe('correct');
expect(r.cost_usd).toBe(0.0021);
expect(r.tokens_in).toBe(102);
});
it('handles array gold_answer', () => {
const pilot: PilotJsonlRecord = {
instance_id: 'i1',
question: 'q?',
gold_answer: ['a', 'b'],
subject: { content: 'a' },
};
const r = fromPilotRecord(pilot, { model: 'm', cell: 'c' });
expect(r.gold_answer).toEqual(['a', 'b']);
});
});
// ─────────────────────────────────────────────────────────────────────────
// End-to-end: pilot reproduction
// ─────────────────────────────────────────────────────────────────────────
describe('report — pilot reproduction (Phase 2 acceptance gate D3)', () => {
it('reproduces 8/20 = 40% substring-match on smoke-records.jsonl', async () => {
const PILOT_PATH = path.resolve(__dirname, '../../../benchmarks/results/phase-2-acceptance-gate/smoke-records.jsonl');
if (!fs.existsSync(PILOT_PATH)) {
console.warn('[skip] smoke-records.jsonl not present; pilot reproduction test skipped');
return;
}
const lines = (await fsp.readFile(PILOT_PATH, 'utf-8')).split('\n').filter(Boolean);
const pilots: PilotJsonlRecord[] = lines.map(l => JSON.parse(l));
const records = pilots.map(p => fromPilotRecord(p, { model: 'qwen3.6-35b-a3b-via-dashscope-direct', cell: 'oracle' }));
const r = await generateReport(records, baseOpts);
const m = r.summary.per_model_per_cell['qwen3.6-35b-a3b-via-dashscope-direct']!.oracle!;
expect(m.n).toBe(20);
// D3 inspection found 8/20 = 40.0% substring-match accuracy.
expect(m.accuracy_normalized).toBeCloseTo(0.40, 2);
});
});