CI / policy (push) Successful in 7s
CI / validate (push) Successful in 1m5s
CI / build (push) Successful in 1m38s
CI / policy (pull_request) Successful in 10s
CI / security (push) Successful in 1m19s
CI / test (push) Successful in 3m29s
CI / validate (pull_request) Successful in 1m42s
CI / benchmark (push) Successful in 4m13s
CI / security (pull_request) Successful in 56s
CI / build (pull_request) Successful in 1m42s
CI / test (pull_request) Successful in 3m8s
CI / images (push) Successful in 1m15s
CI / required (push) Successful in 1s
CI / benchmark (pull_request) Successful in 3m37s
CI / images (pull_request) Successful in 1m11s
CI / required (pull_request) Successful in 1s
Print the calibration and a Markdown table with one aligned row per scenario as soon as it finishes: both planning times, mean, budget, ratio, multiplier, outcome, placements, determinism and budget status. Write directly to stdout so Vitest adds no per-line headers. The complete TSV report still follows the table. Refs #281, #285 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
import {
|
|
BenchmarkMeasurement,
|
|
benchmarkSummaryHeader,
|
|
benchmarkSummaryRow,
|
|
budgetViolations,
|
|
} from './leave-planner-benchmark';
|
|
|
|
const measure = (scenario: string, planningMs: number) =>
|
|
({ scenario, planningMs }) as BenchmarkMeasurement;
|
|
|
|
describe('benchmark budget gate', () => {
|
|
const multipliers = { a: 2 };
|
|
it('accepts a mean within multiplier x calibration', () => {
|
|
expect(budgetViolations([measure('a', 150), measure('a', 250)], 100, multipliers)).toEqual(
|
|
[],
|
|
);
|
|
});
|
|
it('reports measured time, budget, multiplier and calibration when over budget', () => {
|
|
const [message] = budgetViolations(
|
|
[measure('a', 300), measure('a', 320)],
|
|
100,
|
|
multipliers,
|
|
);
|
|
expect(message).toContain('a:');
|
|
expect(message).toContain('measured 310.0 ms');
|
|
expect(message).toContain('budget 200.0 ms');
|
|
expect(message).toContain('multiplier 2');
|
|
expect(message).toContain('calibration 100.0 ms');
|
|
});
|
|
it('fails a scenario without a multiplier', () => {
|
|
expect(budgetViolations([measure('new', 1)], 100, multipliers)).toEqual([
|
|
'new: no budget multiplier defined',
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('benchmark summary table', () => {
|
|
const runs = (planningMs: number[]) =>
|
|
planningMs.map(
|
|
(ms, index) =>
|
|
({
|
|
scenario: 'a',
|
|
planningMs: ms,
|
|
outcome: 'Plan',
|
|
lastCompletedStage: 'dates',
|
|
placements: 3,
|
|
deterministic: index ? 'yes' : 'baseline',
|
|
}) as BenchmarkMeasurement,
|
|
);
|
|
it('aligns rows with the header', () => {
|
|
const [header, separator] = benchmarkSummaryHeader().split('\n');
|
|
const row = benchmarkSummaryRow(runs([150, 250]), 100, { a: 2 });
|
|
expect(row).toHaveLength(header.length);
|
|
expect(separator).toHaveLength(header.length);
|
|
expect(row).toContain('0.15 / 0.25 s');
|
|
expect(row).toContain('Plan (dates)');
|
|
expect(row).toMatch(/\| ok +\|$/);
|
|
});
|
|
it('marks scenarios over budget or without a budget', () => {
|
|
expect(benchmarkSummaryRow(runs([300, 320]), 100, { a: 2 })).toMatch(/\| OVER +\|$/);
|
|
expect(benchmarkSummaryRow(runs([1]), 100, {})).toMatch(/\| no budget \|$/);
|
|
});
|
|
});
|