import {test} from 'node:test'; import assert from 'node:assert/strict'; import {readFileSync, mkdtempSync, rmSync} from 'node:fs'; import {tmpdir} from 'node:os'; import {join} from 'node:path'; import {execFileSync} from 'node:child_process'; import {skillsViewer,isSkillsStory} from './skills-viewer.mjs'; const read = p => readFileSync(p,'utf8'); const topics = ['governance','quality','adoption','measurement','maintenance']; test('all six Skills Adoption pages account for exactly five diagrams and ten sources',()=>{ let count=0; for(const route of ['stage-01-skills-adoption',...topics.map(t=>t==='measurement'?t:`skills-${t}`)]){ const diagrams=[...read(`docs/strategy/${route}.mdx`).matchAll(/{ const name=`strategy-${topic}`;const desktop=JSON.parse(read(`diagrams/${name}.architecture.json`)); const mobile=JSON.parse(read(`diagrams/${name}-mobile.architecture.json`)); const semantic = d=>d.components.map(({pos,size,...n})=>n); assert.deepEqual(semantic(desktop),semantic(mobile)); assert.equal(new Set(desktop.components.map(n=>n.pos[0])).size,3); assert.equal(new Set(mobile.components.map(n=>n.pos[0])).size,1); for(const n of desktop.components){assert(n.tag);assert(n.sublabel.split('\n').length>=4);} const dir=mkdtempSync(join(tmpdir(),'skills-viewer-')); try{ const path=join(dir,'native.html'); execFileSync(process.execPath,['vendor/archify/renderers/architecture/render-architecture.mjs',`diagrams/${name}.architecture.json`,path]); const native=read(path);const html=skillsViewer(native,desktop); assert.equal((html.match(/]*data-node-id=/g)||[]).length,6); assert.equal((html.match(/skillsViewer(native.replace('data-node-id="'+desktop.components[0].id+'"','data-node-id="missing"'),desktop)); const bad=structuredClone(desktop);bad.components[0].sublabel='not a full story';assert.throws(()=>skillsViewer(native,bad)); }finally{rmSync(dir,{recursive:true,force:true});} }); test('domain contracts retain human authority, honest measures and Delivery-first rollout',()=>{ const text=t=>read(`diagrams/strategy-${t}.architecture.json`); assert(text('governance').includes('Author is not sole approver')); assert(text('quality').includes('Critical effect blocks')); assert(text('adoption').includes('Delivery first')&&text('adoption').includes('Later order undecided')); assert(text('adoption').includes('No quotas or rankings')); for(const marker of ['Tracker:','Invoices + review minutes','linked defect records','Anonymous 1–5 survey','Missing buckets = partial','Zero denominator = N/A'])assert(text('measurement').includes(marker),marker); assert(text('maintenance').includes('No automatic reinstatement')); });