Manifest-drevet applier (scripts/kb-update/backfill-status.mjs) over den testede insertMetaField-primitiven + ny ren regel statusForFile (filnavn-token → Reference/ Established Practice, operatør-godkjent vokabular). 7 Reference + 7 Established Practice. Hard per-fil-invariant (én linje, body byte-identisk), idempotent, isMain-guard. 7 tester. Premiss-korreksjon (auditHeaders, ground-truth 2026-07-06): ekte not-due-restanse er 21 Status + 26 Last-updated (STATE sa 21/22). «0 har norsk dato» var falskt — 21/26 Last-updated-gap bærer allerede Sist oppdatert/Dato → relabel-residual; 5 datoløse gir «i dag» ved naiv git → utsatt. 4 dual-header ai-act-*-filer med plain-text «Status: GA» fanget i diff-inspeksjon → revertert (unngår duplikat/motsigelse) → residual (samme plain-blokk ga R20 duplikat Category). Korrigert residual logget i roadmap §R21. Verifisering: test-backfill-status 7/7; git diff +14/-0 (kun Status-linjer, body byte-identisk); not-due Status-missing 21→3; full suite 771/771 exit 0.
87 lines
3.9 KiB
JavaScript
87 lines
3.9 KiB
JavaScript
// 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`);
|
|
}
|
|
});
|