// tests/kb-update/test-classify-ref-type.test.mjs // Spor 1 Step 2 — the pure ref-type classifier: MS-citation is the first-pass proxy // for `reference`, but zero-MS files and methodology/template-shaped paths that DO // cite MS are never silently classified — they carry reviewFlag:true for the Step-4 // edge-set adjudication. Pure core, no disk, deterministic output. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { classifyRefType, classifyCorpus, VALID_TYPES, } from '../../scripts/kb-update/lib/classify-ref-type.mjs'; const MS_CITING = '# Azure AI Search\n\n**Category:** rag\n\n---\n\n## A\n\n' + 'Se https://learn.microsoft.com/azure/search/hybrid-search-overview for detaljer.\n'; const ZERO_MS = '# Vurderingsnotat\n\n**Category:** governance\n\n---\n\n## A\n\n' + 'Ren intern metodetekst uten eksterne kilder.\n'; const METHODOLOGY_SHAPED_MS_CITING = '# Vurderingsmetodikk\n\n**Category:** governance\n\n---\n\n## A\n\n' + 'Rammeverk-steg. Se https://learn.microsoft.com/azure/well-architected/ for bakgrunn.\n'; const REGULATORY_ZERO_MS = '# EU AI Act Art. 6\n\n**Category:** governance\n\n---\n\n## A\n\n' + 'Forordningsteksten: https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32024R1689\n'; test('classifyRefType — MS-citing file → reference, mscite:true, no review flag', () => { const r = classifyRefType({ path: 'skills/ms-ai-engineering/references/rag/azure-ai-search.md', content: MS_CITING }); assert.equal(r.type, 'reference'); assert.equal(r.mscite, true); assert.equal(r.reviewFlag, false); assert.equal(r.signal, 'ms-citation'); }); test('classifyRefType — zero-MS file is NOT silently reference: reviewFlag:true + path-heuristic candidate', () => { const r = classifyRefType({ path: 'skills/ms-ai-governance/references/governance/vurderingsnotat.md', content: ZERO_MS }); assert.equal(r.mscite, false); assert.equal(r.reviewFlag, true); assert.ok(VALID_TYPES.includes(r.type)); }); test('classifyRefType — methodology-shaped path that cites MS → reviewFlag:true (opposite false-positive direction)', () => { const r = classifyRefType({ path: 'skills/ms-ai-governance/references/methodology/vurderingsmetodikk.md', content: METHODOLOGY_SHAPED_MS_CITING, }); assert.equal(r.mscite, true); assert.equal(r.reviewFlag, true); assert.ok(VALID_TYPES.includes(r.type)); }); test('classifyRefType — template-shaped path that cites MS → reviewFlag:true', () => { const r = classifyRefType({ path: 'skills/ms-ai-governance/references/templates/dpia-template.md', content: MS_CITING, }); assert.equal(r.reviewFlag, true); assert.ok(VALID_TYPES.includes(r.type)); }); test('classifyRefType — regulatory text citing eur-lex (zero-MS) → reviewFlag:true, regulatory candidate', () => { const r = classifyRefType({ path: 'skills/ms-ai-governance/references/eu-ai-act/article-6.md', content: REGULATORY_ZERO_MS, }); assert.equal(r.mscite, false); assert.equal(r.reviewFlag, true); assert.equal(r.type, 'regulatory'); }); test('classifyRefType — every emitted type is in VALID_TYPES', () => { const fixtures = [ { path: 'skills/x/references/a.md', content: MS_CITING }, { path: 'skills/x/references/templates/b.md', content: ZERO_MS }, { path: 'skills/x/references/methodology/c.md', content: METHODOLOGY_SHAPED_MS_CITING }, { path: 'skills/x/references/eu/d.md', content: REGULATORY_ZERO_MS }, ]; for (const f of fixtures) { const r = classifyRefType(f); assert.ok(VALID_TYPES.includes(r.type), `${r.type} not in VALID_TYPES`); } }); test('classifyCorpus — relpath-keyed, key-sorted, deterministic across runs', () => { const entries = [ { path: 'skills/z/references/z.md', content: MS_CITING }, { path: 'skills/a/references/a.md', content: ZERO_MS }, { path: 'skills/m/references/m.md', content: METHODOLOGY_SHAPED_MS_CITING }, ]; const m1 = classifyCorpus(entries); const m2 = classifyCorpus([...entries].reverse()); assert.deepEqual(m1, m2); assert.equal(JSON.stringify(m1), JSON.stringify(m2)); assert.deepEqual(Object.keys(m1), [...Object.keys(m1)].sort()); assert.equal(Object.keys(m1).length, 3); for (const entry of Object.values(m1)) { assert.ok(VALID_TYPES.includes(entry.type)); assert.equal(typeof entry.reviewFlag, 'boolean'); assert.equal(typeof entry.mscite, 'boolean'); } });