// tests/kb-update/test-relabel-dialect.test.mjs // TDD for Enhet 1 (decision-b, path A, ⊥ R7) — pure value-preserving dialect relabel of the // Norwegian header labels to their English equivalents on the 51 ref files that carry them: // **Sist oppdatert:** → **Last updated:** (31 files) // **Kategori:** → **Category:** (42 files) [22 files carry both → 73 relabels] // // The applier (relabel-dialect.mjs) is a manifest-driven driver over the pure primitive // relabelHeaderDialect(). The ONLY new production logic is that primitive + the frozen MANIFEST. // This suite pins the primitive's safety contract and the manifest's structural well-formedness. // // Explicitly OUT of Enhet 1 (deferred to later units, per the corrected residual): // - **Dato:** → **Last updated:** (16) — Dato also appears in BODY templates ([YYYY-MM-DD]), // a blind replace would corrupt them; needs a header-scoped ISO-date guard (Unit 2). // - Status backfill (27 none + 4 plain) and the ai-act dual-block dedup (Unit 3). // - decision-trees.md date backfill (Unit 4). import { test } from 'node:test'; import assert from 'node:assert/strict'; import { relabelHeaderDialect, LABEL_MAP, MANIFEST, } from '../../scripts/kb-update/relabel-dialect.mjs'; // ── primitive: value-preserving relabel ──────────────────────────────────── test('relabels **Sist oppdatert:** → **Last updated:**, value byte-identical', () => { const input = '# T\n\n**Sist oppdatert:** 2026-02 (v1.0)\n**Status:** GA\n\n---\n\n## Body\n'; const { content, applied } = relabelHeaderDialect(input); assert.equal(applied.length, 1); assert.match(content, /\*\*Last updated:\*\* 2026-02 \(v1\.0\)/); assert.doesNotMatch(content, /\*\*Sist oppdatert:\*\*/); // Only the label token changed — reversing the sub reconstructs the original exactly. assert.equal(content.replace('**Last updated:**', '**Sist oppdatert:**'), input); }); test('relabels **Kategori:** → **Category:**, value byte-identical', () => { const input = '# T\n\n**Kategori:** AI Security Engineering\n**Type:** reference\n\n## Body\n'; const { content, applied } = relabelHeaderDialect(input); assert.equal(applied.length, 1); assert.match(content, /\*\*Category:\*\* AI Security Engineering/); assert.doesNotMatch(content, /\*\*Kategori:\*\*/); assert.equal(content.replace('**Category:**', '**Kategori:**'), input); }); test('applies BOTH relabels when both norsk labels are present', () => { const input = '# T\n\n**Sist oppdatert:** 2026-06-19\n**Kategori:** X\n**Status:** GA\n\n---\n\n## Body\n'; const { content, applied } = relabelHeaderDialect(input); assert.equal(applied.length, 2); assert.match(content, /\*\*Last updated:\*\* 2026-06-19/); assert.match(content, /\*\*Category:\*\* X/); }); test('header-scoping: a norsk label in the BODY (past first --- / ##) is NOT touched', () => { // The template-contamination trap: only the header block above the first thematic break // or section heading is in scope. const input = '# T\n\n**Kategori:** Real Header Value\n\n---\n\n## Mal\n**Kategori:** [fyll inn]\n'; const { content, applied } = relabelHeaderDialect(input); assert.equal(applied.length, 1); assert.match(content, /\*\*Category:\*\* Real Header Value/); // The body template line survives verbatim. assert.match(content, /## Mal\n\*\*Kategori:\*\* \[fyll inn\]/); }); test('no-op when no norsk label is present (English-dialect file)', () => { const input = '# T\n\n**Last updated:** 2026-06\n**Category:** X\n**Status:** GA\n\n## Body\n'; const { content, applied } = relabelHeaderDialect(input); assert.equal(applied.length, 0); assert.equal(content, input); // byte-identical }); test('idempotent: re-running on the output is a no-op', () => { const input = '# T\n\n**Sist oppdatert:** 2026-02\n**Kategori:** X\n\n## Body\n'; const once = relabelHeaderDialect(input); const twice = relabelHeaderDialect(once.content); assert.equal(twice.applied.length, 0); assert.equal(twice.content, once.content); }); test('collision-guard: throws if the English target label already exists in the header', () => { // A dual-header file (bold **Category:** + norsk **Kategori:**) would duplicate on relabel. const input = '# T\n\n**Category:** X\n**Kategori:** X\n\n## Body\n'; assert.throws(() => relabelHeaderDialect(input), /already present/i); }); test('multi-occurrence-guard: throws if a norsk label appears twice in the header block', () => { const input = '# T\n\n**Kategori:** X\n**Kategori:** Y\n\n## Body\n'; assert.throws(() => relabelHeaderDialect(input), /appears/i); }); test('LABEL_MAP is exactly the two norsk→english pairs of Enhet 1 (no Dato)', () => { const froms = LABEL_MAP.map((p) => p[0]); assert.deepEqual(froms.sort(), ['**Kategori:**', '**Sist oppdatert:**']); // **Dato:** is intentionally excluded (body-template trap → deferred to Unit 2). assert.ok(!froms.some((f) => /Dato/.test(f))); }); // ── MANIFEST: structural well-formedness ─────────────────────────────────── test('MANIFEST: exactly 51 distinct, well-formed reference paths', () => { assert.equal(MANIFEST.length, 51); const set = new Set(MANIFEST); assert.equal(set.size, 51, 'duplicate path in MANIFEST'); for (const p of MANIFEST) { assert.match(p, /^skills\/ms-ai-[a-z]+\/references\/.+\.md$/, p); } }); test('MANIFEST: excludes advisor files already English-normalised by R21', () => { // adr-template / poc-template etc. got their Status via R21 but were already English-dialect // for Category/Last-updated → they must NOT be in this relabel manifest. for (const p of MANIFEST) { assert.ok(!p.endsWith('adr-template.md')); assert.ok(!p.endsWith('poc-template.md')); } });