Build and publish Eldorado documentation / build (pull_request) Successful in 42s
46 lines
3.2 KiB
JavaScript
46 lines
3.2 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFileSync, existsSync, readdirSync} from 'node:fs';
|
|
import {createHash} from 'node:crypto';
|
|
import {calculate} from './ai-kpi.mjs';
|
|
const read = p => readFileSync(p, 'utf8');
|
|
|
|
test('each original metric survives exactly once on its own canonical Measurement page', () => {
|
|
const manifest = JSON.parse(read('research/ai-adoption/measurement-migration.json'));
|
|
const model = JSON.parse(read('research/ai-adoption/strategy-model.json'));
|
|
const report = calculate(JSON.parse(read('scripts/fixtures/ai-kpi-synthetic.json')));
|
|
assert.equal(manifest.metrics.length, 16);
|
|
assert.deepEqual(manifest.metrics.map(m => m.title), model.kpis.map(k => k.name));
|
|
assert.equal(new Set(manifest.metrics.map(m => m.docId)).size, 16);
|
|
assert.equal(manifest.metrics.filter(m => m.status === 'prototype').length, 9);
|
|
assert.equal(manifest.metrics.filter(m => m.status === 'unimplemented').length, 7);
|
|
const overview = read('docs/strategy/measurement/index.mdx');
|
|
for (const metric of manifest.metrics) {
|
|
const page = read(`docs/strategy/${metric.docId}.mdx`);
|
|
assert.equal(metric.url, `/strategy/${metric.docId}/`);
|
|
assert.equal(metric.oldAnchor, metric.docId.split('/').at(-1));
|
|
assert(page.includes(`slug: /${metric.docId}`));
|
|
assert(overview.includes(`./${metric.oldAnchor}.mdx`));
|
|
assert(page.includes('./collection-and-safeguards.mdx'));
|
|
assert(page.includes('not installed collection'));
|
|
assert(page.includes(metric.status === 'prototype' ? 'Prototype calculation' : 'Unimplemented metric'));
|
|
assert.equal(Object.hasOwn(report.kpis, metric.calculationId), metric.status === 'prototype');
|
|
const contract = page.split('{/* contract:start */}\n')[1]?.split('\n{/* contract:end */}')[0];
|
|
assert(contract, metric.title);
|
|
assert.equal(createHash('sha256').update(contract).digest('hex'), metric.contractSha256, metric.title);
|
|
for (const field of ['Numerator','Denominator','Expression','Aggregation','Unit','Eligible population','Exclusions','Events and source','Owner / cadence','Missing evidence','Gaming and limits']) assert.equal(contract.split(`| ${field} |`).length, 2, `${metric.title}: ${field}`);
|
|
}
|
|
assert.equal(readdirSync('docs/strategy/measurement').filter(p => p.endsWith('.mdx')).length, 19);
|
|
assert(!existsSync('docs/strategy/reference/measurement-contracts.mdx'));
|
|
for (const part of manifest.shared) {
|
|
const page = read(`docs/strategy/measurement/${part.slug}.mdx`);
|
|
const body = page.split('{/* preserved:start */}\n')[1]?.split('\n{/* preserved:end */}')[0];
|
|
// Only the cross-page navigation wording changes; hash all original substance.
|
|
const original = body.replace('Use the [metric definitions](./index.mdx#metric-definitions)', 'Use the metric contracts below')
|
|
// The old navigation named nonexistent roadmap gates. Restore only that
|
|
// historical sentence for the migration hash; metric substance stays exact.
|
|
.replace('Use these safeguards throughout the [Stage 01 journey](../stage-01-skills-adoption.mdx)', 'Introduction depends on the [roadmap gates](../roadmap.mdx)');
|
|
assert.equal(createHash('sha256').update(original).digest('hex'), part.sha256);
|
|
}
|
|
});
|