import { describe, expect, it } from 'vitest'; import { collectRollingPhase0ArtifactFiles, planRollingPhase0ArtifactRetention, } from './phase0BaselineArtifactRetention.js'; describe('phase0BaselineArtifactRetention', () => { it('collects only rolling-tag phase-0 artifact files', () => { const rows = collectRollingPhase0ArtifactFiles([ 'phase0_baseline_live_2026-02-27-010203.json', 'phase0_baseline_live_gateway_2026-02-27-010203.md', 'phase0_baseline_live_backend_pi_embedded_2026-02-27-010203.jsonl', 'phase0_baseline_live_backend_native_2026-02-27-010203.json', 'phase0_baseline_live_backend_drift_2026-02-27-010203.md', 'phase0_baseline_live_prune_2026-02-27-010203.json', 'phase0_baseline_live_2026-02-27.json', 'phase0_baseline_live_gateway_2026-02-27.jsonl', 'phase0_baseline_2026-02-25.md', 'phase0_baseline_live_backend_pi_embedded_2026-02-27.md', 'phase0_baseline_live_prune_2026-02-27.md', 'not_a_phase0_file.txt', ]); expect(rows).toHaveLength(6); expect(rows.map((row) => row.family).sort()).toEqual([ 'backend_drift', 'backend_native', 'backend_pi_embedded', 'channel', 'gateway', 'prune', ]); }); it('keeps most recent rolling tags per family and prunes older ones', () => { const files = [ 'phase0_baseline_live_2026-02-27-010203.json', 'phase0_baseline_live_2026-02-27-010203.jsonl', 'phase0_baseline_live_2026-02-27-020304.json', 'phase0_baseline_live_2026-02-27-020304.md', 'phase0_baseline_live_gateway_2026-02-27-010203.json', 'phase0_baseline_live_gateway_2026-02-27-020304.json', 'phase0_baseline_live_backend_pi_embedded_2026-02-27-010203.json', 'phase0_baseline_live_backend_pi_embedded_2026-02-27-020304.json', 'phase0_baseline_live_backend_native_2026-02-27-010203.json', 'phase0_baseline_live_backend_native_2026-02-27-020304.json', 'phase0_baseline_live_backend_drift_2026-02-27-010203.json', 'phase0_baseline_live_backend_drift_2026-02-27-020304.json', 'phase0_baseline_live_prune_2026-02-27-010203.json', 'phase0_baseline_live_prune_2026-02-27-020304.json', 'phase0_baseline_live_2026-02-27.json', 'phase0_baseline_live_prune_2026-02-27.json', ]; const plan = planRollingPhase0ArtifactRetention(files, 1); expect(plan.families).toEqual([ { family: 'channel', total_tags: 2, keep_tags: 1, remove_tags: 1 }, { family: 'gateway', total_tags: 2, keep_tags: 1, remove_tags: 1 }, { family: 'backend_pi_embedded', total_tags: 2, keep_tags: 1, remove_tags: 1 }, { family: 'backend_native', total_tags: 2, keep_tags: 1, remove_tags: 1 }, { family: 'backend_drift', total_tags: 2, keep_tags: 1, remove_tags: 1 }, { family: 'prune', total_tags: 2, keep_tags: 1, remove_tags: 1 }, ]); const removeSet = new Set(plan.remove.map((row) => row.file_name)); expect(removeSet.has('phase0_baseline_live_2026-02-27-010203.json')).toBe(true); expect(removeSet.has('phase0_baseline_live_2026-02-27-010203.jsonl')).toBe(true); expect(removeSet.has('phase0_baseline_live_gateway_2026-02-27-010203.json')).toBe(true); expect(removeSet.has('phase0_baseline_live_backend_pi_embedded_2026-02-27-010203.json')).toBe(true); expect(removeSet.has('phase0_baseline_live_backend_native_2026-02-27-010203.json')).toBe(true); expect(removeSet.has('phase0_baseline_live_backend_drift_2026-02-27-010203.json')).toBe(true); expect(removeSet.has('phase0_baseline_live_prune_2026-02-27-010203.json')).toBe(true); const keepSet = new Set(plan.keep.map((row) => row.file_name)); expect(keepSet.has('phase0_baseline_live_2026-02-27.json')).toBe(false); expect(keepSet.has('phase0_baseline_live_prune_2026-02-27.json')).toBe(false); expect(keepSet.has('phase0_baseline_live_2026-02-27-020304.json')).toBe(true); expect(keepSet.has('phase0_baseline_live_2026-02-27-020304.md')).toBe(true); expect(keepSet.has('phase0_baseline_live_prune_2026-02-27-020304.json')).toBe(true); }); it('supports zero keep limit', () => { const plan = planRollingPhase0ArtifactRetention([ 'phase0_baseline_live_2026-02-27-010203.json', 'phase0_baseline_live_gateway_2026-02-27-010203.json', 'phase0_baseline_live_prune_2026-02-27-010203.md', ], 0); expect(plan.keep).toHaveLength(0); expect(plan.remove.map((row) => row.file_name).sort()).toEqual([ 'phase0_baseline_live_2026-02-27-010203.json', 'phase0_baseline_live_gateway_2026-02-27-010203.json', 'phase0_baseline_live_prune_2026-02-27-010203.md', ]); }); it('rejects negative keep limit', () => { expect(() => planRollingPhase0ArtifactRetention([], -1)).toThrow('keepPerFamily'); }); });