ms-ai-architect/tests/kb-update/test-relabel-dialect.test.mjs
Kjell Tore Guttormsen e999b74eda feat(ms-ai-architect): decision-b Enhet 1 — dialekt-relabel 51 filer (Kategori→Category + Sist oppdatert→Last updated), 73 byte-eksakte swaps [skip-docs]
Ren value-preserving label-relabel av de to norske header-labelene til engelsk på 51 ref-filer (22 bærer begge). Ny testet ren primitiv relabelHeaderDialect() (header-blokk-scoped, kollisjons-/multiforekomst-guard) + manifest-drevet driver relabel-dialect.mjs (frosset 51-fil-manifest, hard per-fil-invariant, idempotent, isMain-guard). **Dato:** bevisst UTE (body-template-felle → Enhet 2). Premiss-korreksjon i roadmap R22: tredje Dato-dialekt (16), 0 bold-duplikater (ikke 4), 1 datoløs (ikke 5), category-none = vindus-artefakt. test-relabel-dialect 11/11; diff +73/-73 0 linjer utover label; suite 782/782 exit 0.
2026-07-06 10:07:52 +02:00

117 lines
5.8 KiB
JavaScript

// 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'));
}
});