/** * Drift lock: the inline platform-capabilities tables embedded in the BA * SKILL.md files (deployed standalone, markdown-only) must stay consistent * with the canonical `lib/capability-catalog.ts`. Edit BOTH or this suite * fails. * * - `platform-capabilities:v1` → carried by create-data-model (C-6), * audit-data-model (DM-019) and audit-cross-ref-code (CODE-006) */ import { readFileSync } from 'node:fs' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' import { PLATFORM_CAPABILITIES } from '../capability-catalog.js' const skillsRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..') const CAPABILITY_CARRIERS = [ 'business-analyse/create-data-model/SKILL.md', 'business-analyse/audit-data-model/SKILL.md', 'business-analyse/audit-cross-ref-code/SKILL.md', ] function readSkill(rel: string): string { return readFileSync(join(skillsRoot, rel), 'utf8') } function extractBlock(md: string, marker: string, file: string): string { const re = new RegExp(`([\\s\\S]*?)`) const m = md.match(re) if (!m) throw new Error(`marker "${marker}" not found in ${file}`) return m[1] } function tableRows(block: string): string[][] { return block .split('\n') .map(l => l.trim()) .filter(l => l.startsWith('|')) .filter(l => !/^\|(\s*:?-+:?\s*\|)+$/.test(l)) .slice(1) // drop the header row .map(l => l.split('|').slice(1, -1).map(c => c.trim())) } function parseListCell(cell: string): string[] { return cell === '—' || cell === '' ? [] : cell.split(',').map(a => a.trim()) } describe.each(CAPABILITY_CARRIERS)('capability-catalog drift — %s', (file) => { it('carries the platform-capabilities:v1 table equal to PLATFORM_CAPABILITIES', () => { const rows = tableRows(extractBlock(readSkill(file), 'platform-capabilities:v1', file)).map(cells => ({ key: cells[0], triggers: parseListCell(cells[1]).sort(), attributeTriggers: parseListCell(cells[2]).sort(), seam: cells[3], useInstead: cells[4], reference: cells[5] === '—' ? undefined : cells[5].replace(/`/g, ''), })) const expected = PLATFORM_CAPABILITIES.map(c => ({ key: c.key, triggers: [...c.triggers].sort(), attributeTriggers: [...(c.attributeTriggers ?? [])].sort(), seam: c.seam, useInstead: c.useInstead, reference: c.reference, })) expect(rows).toEqual(expected) }) })