// tests/kb-update/test-verified-staleness.test.mjs // Spor 3 Port 3 (kadens-judge) — INCREMENTAL stale-since-verified classifier. // // classifyVerifiedStaleness is a PURE function (mirrors verify-out.mjs: it never // touches disk). It answers the cheap, lastmod-visible question Port 3's // incremental pass needs: "which reference files have a source that changed // AFTER we last verified them?" The expensive full-pass (P3d) catches the // drift class this misses. The reporting floor (P3b) reads its output. // // Scope is the Port 1 contract: only `type: reference` files are in correctness // scope. template/methodology/regulatory are exempt (out-of-scope). Files with // no Type header are `unmigrated` (legacy corpus — Spor 1 territory, not judged // here but counted so the migration gap is an honest number). import { test } from 'node:test'; import assert from 'node:assert/strict'; import { classifyVerifiedStaleness, buildFileSourceMap, buildStalenessReport, } from '../../scripts/kb-update/lib/verified-staleness.mjs'; const f = (over) => ({ path: 'skills/x/references/a.md', type: 'reference', verified: '2026-06-01', newestSourceLastmod: '2026-05-01', ...over, }); test('reference + source changed AFTER verified → flagged stale-since-verified', () => { const out = classifyVerifiedStaleness([f({ verified: '2026-06-01', newestSourceLastmod: '2026-06-15' })]); assert.equal(out.flagged.length, 1); assert.equal(out.flagged[0].reason, 'stale-since-verified'); assert.equal(out.counts.stale, 1); }); test('reference + source older than verified → fresh, not flagged', () => { const out = classifyVerifiedStaleness([f({ verified: '2026-06-01', newestSourceLastmod: '2026-05-01' })]); assert.equal(out.flagged.length, 0); assert.equal(out.counts.fresh, 1); }); test('reference + source lastmod EQUALS verified → fresh (strict >, mirrors report-changes)', () => { const out = classifyVerifiedStaleness([f({ verified: '2026-06-15', newestSourceLastmod: '2026-06-15' })]); assert.equal(out.flagged.length, 0); assert.equal(out.counts.fresh, 1); }); test('reference declared but verified missing → flagged unverified (contract breach)', () => { const out = classifyVerifiedStaleness([f({ verified: null, newestSourceLastmod: '2026-05-01' })]); assert.equal(out.flagged.length, 1); assert.equal(out.flagged[0].reason, 'unverified'); assert.equal(out.counts.unverified, 1); }); test('reference + verified set + NO tracked source → fresh (incremental is lastmod-only; full-pass covers)', () => { const out = classifyVerifiedStaleness([f({ verified: '2026-06-01', newestSourceLastmod: null })]); assert.equal(out.flagged.length, 0); assert.equal(out.counts.fresh, 1); }); test('template / methodology / regulatory → out-of-scope, never flagged', () => { const out = classifyVerifiedStaleness([ f({ type: 'template', verified: null }), f({ type: 'methodology', verified: null }), f({ type: 'regulatory', verified: null }), ]); assert.equal(out.flagged.length, 0); assert.equal(out.counts.outOfScope, 3); }); test('no Type header (legacy) → unmigrated, counted but not flagged', () => { const out = classifyVerifiedStaleness([f({ type: null, verified: null, newestSourceLastmod: '2026-06-15' })]); assert.equal(out.flagged.length, 0); assert.equal(out.counts.unmigrated, 1); }); test('YYYY-MM verified normalizes to -01 → June-15 source is stale against June-month verify', () => { const out = classifyVerifiedStaleness([f({ verified: '2026-06', newestSourceLastmod: '2026-06-15' })]); assert.equal(out.flagged.length, 1); assert.equal(out.flagged[0].reason, 'stale-since-verified'); }); test('flagged carries path + verified + newestSourceLastmod for the report/floor', () => { const out = classifyVerifiedStaleness([ f({ path: 'skills/s/references/p.md', verified: '2026-01-01', newestSourceLastmod: '2026-06-15' }), ]); const e = out.flagged[0]; assert.equal(e.path, 'skills/s/references/p.md'); assert.equal(e.verified, '2026-01-01'); assert.equal(e.newestSourceLastmod, '2026-06-15'); }); test('mixed corpus aggregates counts; total = input length', () => { const out = classifyVerifiedStaleness([ f({ verified: '2026-01-01', newestSourceLastmod: '2026-06-15' }), // stale f({ verified: '2026-06-01', newestSourceLastmod: '2026-05-01' }), // fresh f({ verified: null }), // unverified f({ type: 'template', verified: null }), // out-of-scope f({ type: null, verified: null }), // unmigrated ]); assert.equal(out.counts.total, 5); assert.equal(out.counts.stale, 1); assert.equal(out.counts.fresh, 1); assert.equal(out.counts.unverified, 1); assert.equal(out.counts.outOfScope, 1); assert.equal(out.counts.unmigrated, 1); assert.equal(out.flagged.length, 2); // stale + unverified }); test('empty input → empty flagged, zeroed counts', () => { const out = classifyVerifiedStaleness([]); assert.equal(out.flagged.length, 0); assert.equal(out.counts.total, 0); assert.equal(out.counts.stale, 0); }); // --- buildFileSourceMap: invert the registry (URL→files ⇒ file→newest lastmod) --- // Mirrors report-changes' grouping loop, but extracted as a PURE helper so the // incremental pass and the full-pass (P3d) share one inversion. test('buildFileSourceMap — single tracked URL maps its file to the lastmod', () => { const reg = { urls: { 'https://x': { status: 'tracked', sitemap_lastmod: '2026-06-01', reference_files: ['a.md'] } } }; const m = buildFileSourceMap(reg); assert.equal(m.get('a.md'), '2026-06-01'); }); test('buildFileSourceMap — multiple URLs for one file → newest lastmod wins', () => { const reg = { urls: { 'https://x': { status: 'tracked', sitemap_lastmod: '2026-03-01', reference_files: ['a.md'] }, 'https://y': { status: 'tracked', sitemap_lastmod: '2026-06-15', reference_files: ['a.md'] }, 'https://z': { status: 'tracked', sitemap_lastmod: '2026-05-01', reference_files: ['a.md'] }, } }; assert.equal(buildFileSourceMap(reg).get('a.md'), '2026-06-15'); }); test('buildFileSourceMap — non-tracked status and missing lastmod are skipped', () => { const reg = { urls: { 'https://x': { status: 'not_in_sitemap', sitemap_lastmod: '2026-06-01', reference_files: ['a.md'] }, 'https://y': { status: 'tracked', sitemap_lastmod: null, reference_files: ['a.md'] }, } }; assert.equal(buildFileSourceMap(reg).has('a.md'), false); }); test('buildFileSourceMap — empty / garbage registry → empty map', () => { assert.equal(buildFileSourceMap({}).size, 0); assert.equal(buildFileSourceMap(null).size, 0); assert.equal(buildFileSourceMap({ urls: {} }).size, 0); }); // --- buildStalenessReport: assemble the full incremental report (pure; reader injected) --- const REG = { last_poll: '2026-06-23T18:09:30Z', urls: { 'https://x': { status: 'tracked', sitemap_lastmod: '2026-06-15', reference_files: ['stale.md'] }, 'https://y': { status: 'tracked', sitemap_lastmod: '2026-01-01', reference_files: ['fresh.md'] }, 'https://z': { status: 'tracked', sitemap_lastmod: '2026-06-10', reference_files: ['gone.md'] }, } }; const READER = (p) => ({ 'stale.md': { type: 'reference', verified: '2026-02-01' }, 'fresh.md': { type: 'reference', verified: '2026-06-01' }, 'gone.md': null, // deleted on disk — reader signals absence }[p] ?? null); test('buildStalenessReport — stamps metadata, joins headers to lastmod, classifies', () => { const r = buildStalenessReport(REG, READER, { today: '2026-06-29' }); assert.equal(r.generated_at, '2026-06-29'); assert.equal(r.last_poll, '2026-06-23T18:09:30Z'); assert.equal(r.counts.stale, 1); assert.equal(r.counts.fresh, 1); assert.equal(r.flagged.length, 1); assert.equal(r.flagged[0].path, 'stale.md'); assert.equal(r.flagged[0].reason, 'stale-since-verified'); }); test('buildStalenessReport — files the reader returns null for (deleted) are skipped entirely', () => { const r = buildStalenessReport(REG, READER, { today: '2026-06-29' }); assert.equal(r.counts.total, 2); // gone.md skipped, not counted assert.ok(!r.flagged.some((f) => f.path === 'gone.md')); }); test('buildStalenessReport — flagged sorted: stale-since-verified before unverified, newest drift first', () => { const reg = { last_poll: null, urls: { 'https://a': { status: 'tracked', sitemap_lastmod: '2026-06-10', reference_files: ['s-old.md'] }, 'https://b': { status: 'tracked', sitemap_lastmod: '2026-06-20', reference_files: ['s-new.md'] }, 'https://c': { status: 'tracked', sitemap_lastmod: '2026-06-15', reference_files: ['u.md'] }, } }; const reader = (p) => ({ 's-old.md': { type: 'reference', verified: '2026-01-01' }, 's-new.md': { type: 'reference', verified: '2026-01-01' }, 'u.md': { type: 'reference', verified: null }, }[p] ?? null); const r = buildStalenessReport(reg, reader, { today: '2026-06-29' }); assert.deepEqual(r.flagged.map((f) => f.path), ['s-new.md', 's-old.md', 'u.md']); });