gstack/test/helpers/capture-parity-baseline.tes...

91 lines
3.7 KiB
TypeScript

/**
* Unit tests for parity baseline capture.
*
* Free. Reads the live repo state via captureBaseline() and asserts
* shape + invariants, not specific numbers (which drift release-over-release).
*/
import { describe, test, expect } from 'bun:test';
import * as fs from 'fs';
import * as path from 'path';
import { captureBaseline, diffBaselines, type ParityBaseline } from './capture-parity-baseline';
const REPO_ROOT = path.resolve(import.meta.dir, '..', '..');
describe('capture-parity-baseline', () => {
test('produces a shaped baseline for the current repo', () => {
const baseline = captureBaseline({ repoRoot: REPO_ROOT, tag: 'unit-test' });
expect(baseline.tag).toBe('unit-test');
expect(baseline.totalSkills).toBeGreaterThan(20);
expect(baseline.totalCorpusBytes).toBeGreaterThan(100_000);
expect(baseline.topHeaviest.length).toBeGreaterThan(0);
expect(baseline.topHeaviest.length).toBeLessThanOrEqual(10);
expect(baseline.topHeaviest[0]!.skillMdBytes).toBeGreaterThan(0);
// Top 1 should be ≥ Top 2 (sort invariant)
if (baseline.topHeaviest.length >= 2) {
expect(baseline.topHeaviest[0]!.skillMdBytes).toBeGreaterThanOrEqual(
baseline.topHeaviest[1]!.skillMdBytes,
);
}
});
test('each skill entry has byte + line + token estimates', () => {
const baseline = captureBaseline({ repoRoot: REPO_ROOT });
for (const skill of Object.values(baseline.skills)) {
expect(skill.skillMdBytes).toBeGreaterThan(0);
expect(skill.skillMdLines).toBeGreaterThan(0);
expect(skill.estTokens).toBeGreaterThan(0);
// ~4 chars/token heuristic
expect(skill.estTokens).toBeCloseTo(skill.skillMdBytes / 4, -2);
}
});
test('diffBaselines returns expected deltas', () => {
const before: ParityBaseline = {
tag: 'before',
capturedAt: '2026-01-01T00:00:00Z',
capturedFromCommit: 'abc',
capturedFromBranch: 'main',
totalSkills: 2,
totalCorpusBytes: 1000,
estTotalCatalogTokens: 100,
topHeaviest: [],
skills: {
foo: { skill: 'foo', skillMdBytes: 600, skillMdLines: 10, estTokens: 150, tmplBytes: 300, descriptionLen: 50, hasGateEval: true, hasPeriodicEval: false },
bar: { skill: 'bar', skillMdBytes: 400, skillMdLines: 8, estTokens: 100, tmplBytes: 200, descriptionLen: 30, hasGateEval: false, hasPeriodicEval: false },
},
};
const after: ParityBaseline = {
...before,
tag: 'after',
totalCorpusBytes: 700,
estTotalCatalogTokens: 60,
skills: {
foo: { ...before.skills.foo!, skillMdBytes: 400 },
bar: { ...before.skills.bar!, skillMdBytes: 300 },
},
};
const diff = diffBaselines(before, after);
expect(diff.totalCorpusDelta).toBe(-300);
expect(diff.totalCorpusDeltaPct).toBeCloseTo(-30, 1);
expect(diff.catalogTokensDelta).toBe(-40);
expect(diff.perSkill.length).toBe(2);
// Sorted by abs delta descending
expect(diff.perSkill[0]!.skill).toBe('foo');
expect(diff.perSkill[0]!.deltaBytes).toBe(-200);
expect(diff.perSkill[1]!.skill).toBe('bar');
});
test('v1.44.1 baseline file exists with expected shape', () => {
const baselinePath = path.join(REPO_ROOT, 'test', 'fixtures', 'parity-baseline-v1.44.1.json');
expect(fs.existsSync(baselinePath)).toBe(true);
const baseline = JSON.parse(fs.readFileSync(baselinePath, 'utf-8')) as ParityBaseline;
expect(baseline.tag).toBe('v1.44.1');
expect(baseline.totalSkills).toBeGreaterThan(40);
// Document the v1.44.1 snapshot as the v1→v2 baseline reference.
// Compression in v1.45+ should drop totalCorpusBytes; this assertion
// anchors the "v1 was XX MB" claim in the CHANGELOG to a real file.
expect(baseline.totalCorpusBytes).toBeGreaterThan(2_000_000);
});
});