// tests/kb-update/test-backfill-category.test.mjs // TDD for the Category-backfill driver (R20). RX-OPS2 makes it importable (isMain // guard + extracted run()/planCategoryBackfill) so its deterministic contract can be // pinned without executing the corpus scan as an import side effect, and routes its // writes through the crash-safe atomic writer. The pure, frozen contract: // - FOLDER_CATEGORY: the 5 operator-approved folder→category entries (2026-07-06). // - categoryForFile: immediate-parent-folder lookup; unknown folder → null. // - planCategoryBackfill: reads a corpus root, plans insert-only Category lines behind // the same one-line/byte-identical invariant as the sibling drivers; files that // already carry Category are idempotently skipped; unknown folders are unmatched // (never written). import { test } from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join, dirname } from 'node:path'; import { FOLDER_CATEGORY, categoryForFile, planCategoryBackfill, } from '../../scripts/kb-update/backfill-category.mjs'; function withTmp(fn) { const dir = mkdtempSync(join(tmpdir(), 'bcat-test-')); try { return fn(dir); } finally { rmSync(dir, { recursive: true, force: true }); } } function writeFile(root, rel, content) { const path = join(root, rel); mkdirSync(dirname(path), { recursive: true }); writeFileSync(path, content, 'utf8'); } test('FOLDER_CATEGORY — frozen operator-approved taxonomy (5 folders, 2026-07-06)', () => { assert.deepEqual(FOLDER_CATEGORY, { architecture: 'Solution Architecture & Advisory', platforms: 'Microsoft AI Platforms', development: 'Microsoft AI Platforms', 'responsible-ai': 'Responsible AI & Governance', 'mlops-genaiops': 'MLOps & GenAIOps', }); }); test('categoryForFile — maps immediate-parent folder; unknown folder → null', () => { assert.equal(categoryForFile('skills/x/references/architecture/foo.md'), 'Solution Architecture & Advisory'); assert.equal(categoryForFile('skills/x/references/mlops-genaiops/bar.md'), 'MLOps & GenAIOps'); assert.equal(categoryForFile('skills/x/references/responsible-ai/baz.md'), 'Responsible AI & Governance'); assert.equal(categoryForFile('skills/x/references/unknown-folder/qux.md'), null); }); test('planCategoryBackfill — plans a Category-less file in a known folder (one line, right value)', () => { withTmp((root) => { writeFile( root, 'skills/ms-ai-engineering/references/mlops-genaiops/x.md', '# X\n\n**Status:** Reference\n\n---\n\nBody.\n', ); const { planned, unmatched } = planCategoryBackfill(root); assert.equal(unmatched.length, 0); assert.equal(planned.length, 1); assert.equal(planned[0].cat, 'MLOps & GenAIOps'); // Insert-only invariant: exactly one extra line, the Category line. assert.match(planned[0].out, /^\*\*Category:\*\* MLOps & GenAIOps$/m); }); }); test('planCategoryBackfill — file already carrying Category is skipped (idempotent)', () => { withTmp((root) => { writeFile( root, 'skills/ms-ai-engineering/references/mlops-genaiops/x.md', '# X\n\n**Category:** MLOps & GenAIOps\n**Status:** Reference\n\n---\n\nBody.\n', ); const { planned, unmatched } = planCategoryBackfill(root); assert.equal(planned.length, 0); assert.equal(unmatched.length, 0); }); }); test('planCategoryBackfill — file in an unknown folder is unmatched, never planned for a write', () => { withTmp((root) => { writeFile(root, 'skills/ms-ai-x/references/mystery/x.md', '# X\n\n**Status:** Reference\n\n---\n\nBody.\n'); const { planned, unmatched } = planCategoryBackfill(root); assert.equal(planned.length, 0); assert.equal(unmatched.length, 1); assert.match(unmatched[0], /mystery/); }); });