ms-ai-architect/tests/kb-update/test-dedup-plain-header.test.mjs
Kjell Tore Guttormsen de0d94cbc1 feat(ms-ai-architect): R22 decision-b Enhet 3 — Status-backfill 25 none + ai-act dual-header-dedup 4 (Missing Status/Last-updated 29+4→0) [skip-docs]
To operasjoner, én økt (⊥ R7), begge ren metadata-normalisering (verdi aldri fabrikkert).

Premiss-korreksjon (ground truth 2026-07-07): roadmap sa «27 none + 4 ai-act».
Målt: 29 mangler bold **Status:** = 25 rene none + 4 ai-act (plain Status: GA).
De «27» inkluderte 2 for mye — 2 filer (custom-dashboards-ai-operations,
zero-trust-ai-services) har bold **Status:** KUN forbi byte 500 (present for
full-fil-audit, usynlig for 500B header-parser) → egen header-slanking-residual
(§8-register), utenfor Enhet 3.

Op A — Status-backfill 25 rene none: utvidet backfill-status.mjs MANIFEST 14→39
(samme statusForFile + insertMetaField + hard per-fil-invariant, idempotent skip
på de 14 R21-gjorte). Alle 25 → **Status:** Established Practice (ingen matcher
template|matrix|benchmarks|register). Diff +25/-0.

Op B — ai-act dual-header-dedup (4 filer): ny driver dedup-plain-header.mjs + 2
rene primitiver i transform.mjs — boldifyPlainField (plain→bold, verdi bevart
byte-eksakt, header-scoped, idempotent) + dropRedundantPlainField (sletter plain
KUN når bold m/ identisk verdi beviser redundans; kaster ved avvik/manglende bold).
Per fil: plain Last updated: + Status: GA → bold (2026-06-18/2026-02, GA bevart),
redundant plain Category: fjernet. Hard per-fil-invariant (net -1 linje, begge
felt bold m/ bevart verdi, ingen plain-header igjen, body byte-identisk). Diff -12/+8.

Verifisering: test-backfill-status 8/8 + test-dedup-plain-header 13/13; audit
Missing Status 29→0, Missing English Last updated 4→0; skills-diff 29 filer
+33/-12 (kun **Status:** + 8 bold-swaps), diff-kontekst inspisert per fil; begge
drivere idempotent (re-run 0 writes); suite 806/806 exit 0; none=8 uendret (Enhet 4).
2026-07-07 07:45:27 +02:00

123 lines
6.4 KiB
JavaScript

// tests/kb-update/test-dedup-plain-header.test.mjs
// TDD for Enhet 3 Op B — the dual-header plain→bold dedup on the 4 ms-ai-governance
// ai-act-* files. Those files carry an authored, PLAIN-TEXT block
// Last updated: <date>
// Status: GA
// Category: <value> ← redundant: a bold **Category:** <same value> already exists
// (R20 inserted the bold Category; the plain block is the original dual header). This is NOT a
// derive-a-value backfill (backfill-status.mjs owns that) — the authored values are PRESERVED
// byte-exact; only their label decoration is normalized to bold, and the provably-redundant
// plain Category line is removed. Two new pure primitives + a pure composition are pinned here.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { boldifyPlainField, dropRedundantPlainField } from '../../scripts/kb-update/lib/transform.mjs';
import { dedupPlainHeader, MANIFEST } from '../../scripts/kb-update/dedup-plain-header.mjs';
// An ai-act-shaped fixture: bold Type+Category (Category from R20), then the plain block,
// then a body that itself mentions "Status:" in prose (must never be touched).
const FIXTURE = [
'# EU AI Act — Systematisk Klassifiseringsmetodikk',
'**Type:** regulatory',
'**Category:** Responsible AI & Governance',
'',
'Last updated: 2026-06-18',
'Status: GA',
'Category: Responsible AI & Governance',
'',
'---',
'',
'## Innhold',
'',
'A body paragraph that says Status: draft in prose — must be left alone.',
'',
].join('\n');
// ── boldifyPlainField ────────────────────────────────────────────────────────
test('boldifyPlainField: plain header field → bold, value preserved byte-exact', () => {
const out = boldifyPlainField(FIXTURE, 'Last updated');
assert.ok(out.includes('**Last updated:** 2026-06-18'), 'bold line present');
assert.ok(!/^Last updated:/m.test(out.split('\n---')[0]), 'plain header line gone');
});
test('boldifyPlainField: idempotent — a bold field already present is unchanged', () => {
const once = boldifyPlainField(FIXTURE, 'Status');
const twice = boldifyPlainField(once, 'Status');
assert.equal(twice, once);
});
test('boldifyPlainField: no plain field in header → unchanged', () => {
assert.equal(boldifyPlainField(FIXTURE, 'Nonexistent'), FIXTURE);
});
test('boldifyPlainField: never touches a match in the body (below the header region)', () => {
const out = boldifyPlainField(FIXTURE, 'Status');
assert.ok(out.includes('says Status: draft in prose'), 'body prose untouched');
// exactly one bold Status inserted (the header one), body "Status:" not bolded
assert.equal((out.match(/\*\*Status:\*\*/g) || []).length, 1);
});
test('boldifyPlainField: body byte-identical (only the header line changes)', () => {
const out = boldifyPlainField(FIXTURE, 'Status');
const bodyOf = (c) => c.slice(c.indexOf('\n---'));
assert.equal(bodyOf(out), bodyOf(FIXTURE));
});
// ── dropRedundantPlainField ──────────────────────────────────────────────────
test('dropRedundantPlainField: drops the plain line when a bold field with the same value exists', () => {
const out = dropRedundantPlainField(FIXTURE, 'Category');
const header = out.split('\n---')[0];
assert.ok(/\*\*Category:\*\* Responsible AI & Governance/.test(header), 'bold Category kept');
assert.ok(!/^Category:/m.test(header), 'plain Category removed');
assert.equal(out.split('\n').length, FIXTURE.split('\n').length - 1, 'exactly one line removed');
});
test('dropRedundantPlainField: throws when plain value ≠ bold value (not redundant, human decision)', () => {
const mismatched = FIXTURE.replace('Category: Responsible AI & Governance', 'Category: Something Else');
assert.throws(() => dropRedundantPlainField(mismatched, 'Category'), /not redundant|≠/);
});
test('dropRedundantPlainField: throws when no bold field exists to prove redundancy', () => {
const noBold = FIXTURE.replace('**Category:** Responsible AI & Governance\n', '');
assert.throws(() => dropRedundantPlainField(noBold, 'Category'), /no bold/i);
});
test('dropRedundantPlainField: no-op when the plain line is absent (idempotent)', () => {
const once = dropRedundantPlainField(FIXTURE, 'Category');
assert.equal(dropRedundantPlainField(once, 'Category'), once);
});
// ── dedupPlainHeader (full composition) ──────────────────────────────────────
test('dedupPlainHeader: boldifies Last updated + Status, drops redundant plain Category', () => {
const out = dedupPlainHeader(FIXTURE);
const header = out.split('\n---')[0];
assert.ok(/\*\*Last updated:\*\* 2026-06-18/.test(header), 'Last updated bolded, value preserved');
assert.ok(/\*\*Status:\*\* GA/.test(header), 'Status bolded, GA preserved');
assert.equal((header.match(/\*\*Category:\*\*/g) || []).length, 1, 'exactly one bold Category');
assert.ok(!/^(Last updated|Status|Category):/m.test(header), 'no plain header fields remain');
});
test('dedupPlainHeader: net one line removed, body byte-identical', () => {
const out = dedupPlainHeader(FIXTURE);
assert.equal(out.split('\n').length, FIXTURE.split('\n').length - 1);
const bodyOf = (c) => c.slice(c.indexOf('\n---'));
assert.equal(bodyOf(out), bodyOf(FIXTURE));
});
test('dedupPlainHeader: idempotent — a second pass is a no-op', () => {
const once = dedupPlainHeader(FIXTURE);
assert.equal(dedupPlainHeader(once), once);
});
// ── MANIFEST ─────────────────────────────────────────────────────────────────
test('MANIFEST: exactly the 4 dual-header ai-act-* files', () => {
assert.equal(MANIFEST.length, 4);
assert.equal(new Set(MANIFEST).size, 4, 'no duplicates');
const expected = [
'skills/ms-ai-governance/references/responsible-ai/ai-act-classification-methodology.md',
'skills/ms-ai-governance/references/responsible-ai/ai-act-deployer-obligations.md',
'skills/ms-ai-governance/references/responsible-ai/ai-act-fria-template.md',
'skills/ms-ai-governance/references/responsible-ai/ai-act-provider-obligations.md',
];
for (const p of expected) assert.ok(MANIFEST.includes(p), `missing ${p}`);
});