// tests/kb-update/test-backfill-status.test.mjs // TDD for R21 — Status backfill on the 18 English-dialect not-due reference files that // lack **Status:**. The applier (backfill-status.mjs) is a manifest-driven driver over the // already-tested insertMetaField primitive; the ONLY new production logic is the pure // deterministic value rule statusForFile() + the frozen MANIFEST. This suite pins both: // - statusForFile: filename token (template|matrix|benchmarks|register) → 'Reference', // else 'Established Practice'. Operator-approved vocabulary (2026-07-06), scope-confirmed // 18 files (ground truth: not-due ∩ missing-**Status:** ∩ English-dialect). // - MANIFEST self-consistency: 18 distinct entries, each value === statusForFile(path). // The 21 Last-updated-relabels + 5 unreliable-git + 3 Norwegian-dialect-Status are OUT of // R21 (corrected decision-b residual) and intentionally NOT in this manifest. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { statusForFile, MANIFEST, ALLOWED_STATUS } from '../../scripts/kb-update/backfill-status.mjs'; // The 14 scope-confirmed R21 targets (clean advisor/architecture). The 4 ms-ai-governance // ai-act-* files that matched the token rule are NOT here: they carry a plain-text `Status: GA` // in a dual-header block (bold-regex-invisible), so they are deferred to the decision-b residual. const REFERENCE = [ 'adr-template.md', 'ai-utredning-template.md', 'capacity-feasibility-benchmarks.md', 'diagram-prompt-templates.md', 'licensing-matrix.md', 'poc-template.md', 'source-traceability-assumption-register.md', ]; const ESTABLISHED = [ 'alternativanalyse-methodology.md', 'cost-models.md', 'decision-trees.md', 'migration-patterns.md', 'public-sector-checklist.md', 'regional-availability-verification.md', 'security.md', ]; test('statusForFile: artifact-token filenames → Reference', () => { for (const b of REFERENCE) assert.equal(statusForFile(b), 'Reference', b); }); test('statusForFile: methodology/guidance/obligation filenames → Established Practice', () => { for (const b of ESTABLISHED) assert.equal(statusForFile(b), 'Established Practice', b); }); test('statusForFile: keys on basename only, not on ancestor folders', () => { // A folder named "templates" must not flip a guidance file to Reference. assert.equal(statusForFile('skills/x/references/templates/migration-patterns.md'), 'Established Practice'); // Full plugin-relative path resolves to the same value as the bare basename. assert.equal(statusForFile('skills/ms-ai-advisor/references/architecture/poc-template.md'), 'Reference'); }); test('statusForFile: always returns an allowed value', () => { for (const b of [...REFERENCE, ...ESTABLISHED, 'anything-else.md']) { assert.ok(ALLOWED_STATUS.includes(statusForFile(b)), b); } }); test('MANIFEST: exactly 14 distinct entries, each value === statusForFile(path)', () => { assert.equal(MANIFEST.length, 14); const paths = new Set(MANIFEST.map((m) => m.path)); assert.equal(paths.size, 14, 'duplicate path in MANIFEST'); for (const { path, status } of MANIFEST) { assert.ok(ALLOWED_STATUS.includes(status), `bad status for ${path}`); assert.equal(status, statusForFile(path), `manifest/rule mismatch for ${path}`); } }); test('MANIFEST: 7 Reference + 7 Established Practice (scope-confirmed split)', () => { const ref = MANIFEST.filter((m) => m.status === 'Reference').length; const est = MANIFEST.filter((m) => m.status === 'Established Practice').length; assert.equal(ref, 7); assert.equal(est, 7); }); test('MANIFEST: excludes the 4 dual-header ai-act-* files (decision-b residual)', () => { const deferred = [ 'ai-act-classification-methodology.md', 'ai-act-deployer-obligations.md', 'ai-act-fria-template.md', 'ai-act-provider-obligations.md', ]; for (const d of deferred) { assert.ok(!MANIFEST.some((m) => m.path.endsWith(d)), `${d} must be deferred, not in MANIFEST`); } });