okr/tests/package-shape.test.mjs
Kjell Tore Guttormsen 3a0cbcfbf9 feat(okr): deterministisk skriveledd for status.md (1.10.0)
Kjeden /okr:rapport -> /okr:sporing -> status.md var beskrevet i prosa, men
manglet et mekanisk ledd: ingenting foerte en generert rad inn i status.md --
fila coaching-hook teller at-risk-KR i, /okr:moeter bygger agenda fra, og
/okr:oppsett arkiver leser sluttscorer fra. Rot-aarsaken var at HELE
sporings-stien var lesende (ingen Write/Edit/Bash i allowed-tools).

scripts/syklus-status.mjs tar confidence som JSON paa stdin og bygger radene
gjennom statusrapport() i lib/syklus-rapport.mjs -- samme kode som
tertialrapporten. Aritmetikken kan derfor ikke drifte fra /okr:rapport, fordi
det ikke finnes en andre implementasjon av den. En LLM skriver ikke av et tall
paa veien, og en maskin utleder ikke et trafikklys: beslutning 9 staar, presist
formulert som at generatoren PLASSERER en etikett den faar inn som data og
UTLEDER aldri en.

Haandhevet i kode, ikke i prosa: lukket vokabular (On Track/At Risk/Off Track),
full dekning (en tom confidence-celle ville lest som groenn hos hver konsument),
typo-fangst paa ukjente KR-navn, og kuratert-fil-vern -- en status.md uten
provenans-noekkelen `kilde: sporing` er haandholdt og overskrives aldri (samme
mekanikk som innboks-write bruker med `kilde: innboks`).

Suite 329 -> 343. Fem vakter mutasjons-verifisert: rad-drift mot
tertialrapporten, vokab, dekning (baade alene og sammen med vokab-vakten som
overlapper den), og kuratert-vernet.
2026-08-10 20:56:26 +02:00

94 lines
3.9 KiB
JavaScript

// package-shape.test.mjs
// Step 10 (A1): package.json-kontrakten for det bevisste zero-dep-bruddet.
// Verifiserer at dep-laget er EXACT-pinnet (ingen ^/~/*), at engines-gulvet er
// satt (unpdf krever node >= 22), at pakken er ESM (type: module), at versjonen
// er 1.10.0 (S60: det uwirede leddet) paa ALLE shippede flater, og at .npmrc slaar av
// install-scripts (Shai-Hulud / supply-chain). Zero npm deps i selve testen.
// Moenster: tests/frontmatter.test.mjs (les fil, assert struktur).
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync, existsSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const PKG = join(ROOT, 'package.json');
const NPMRC = join(ROOT, '.npmrc');
const LOCK = join(ROOT, 'package-lock.json');
// De fire pure-JS-konverterings-deps fra A0 pre-flight (audit 0 vulnerabilities).
const EXPECTED_DEPS = ['mammoth', 'turndown', 'postal-mime', 'unpdf'];
function readPkg() {
return JSON.parse(readFileSync(PKG, 'utf8'));
}
test('package.json: type module + version 1.10.0 (minor)', () => {
const pkg = readPkg();
assert.equal(pkg.type, 'module');
assert.equal(pkg.version, '1.10.0');
});
test('package.json: engines.node-gulv satt (unpdf krever >= 22)', () => {
const pkg = readPkg();
assert.ok(pkg.engines && pkg.engines.node, 'engines.node mangler');
assert.equal(pkg.engines.node, '>=22');
});
test('package.json: alle dependencies EXACT-pinnet (ingen ^/~/*)', () => {
const pkg = readPkg();
assert.ok(pkg.dependencies, 'dependencies mangler');
for (const dep of EXPECTED_DEPS) {
assert.ok(pkg.dependencies[dep], `dep mangler: ${dep}`);
}
for (const [name, version] of Object.entries(pkg.dependencies)) {
assert.match(
version,
/^\d+\.\d+\.\d+$/,
`dep ${name} er ikke exact-pinnet: ${version}`,
);
}
});
test('.npmrc: install-scripts avslaatt (supply-chain-vern)', () => {
const npmrc = readFileSync(NPMRC, 'utf8');
assert.match(npmrc, /^ignore-scripts\s*=\s*true$/m);
});
test('package-lock.json: finnes og pinner transitive deps med integrity', () => {
assert.ok(existsSync(LOCK), 'package-lock.json mangler');
const lock = JSON.parse(readFileSync(LOCK, 'utf8'));
const entries = Object.entries(lock.packages ?? {}).filter(([k]) => k !== '');
assert.ok(entries.length >= EXPECTED_DEPS.length, 'lockfile uten pakke-oppfoeringer');
for (const [name, meta] of entries) {
if (meta.link) continue;
assert.ok(meta.integrity, `lockfile-oppfoering uten integrity: ${name}`);
assert.match(meta.version ?? '', /^\d/, `lockfile-oppfoering uten versjon: ${name}`);
}
});
// R3 (review.md 5e61ae0d): package.json er `private: true` og shipper ALDRI -- versjons-
// assertet over voktet dermed den ene flaten brukeren aldri ser. Polyrepo-ritualet
// (katalog-ref pinnet til release-tag) forutsetter at alle flater bumpes SAMTIDIG, saa en
// delvis bump skal bli ROED. Forventet versjon utledes fra package.json (ett sted aa endre).
const VERSION_SURFACES = [
{ file: '.claude-plugin/plugin.json', re: /"version":\s*"([^"]+)"/ },
{ file: 'README.md', re: /img\.shields\.io\/badge\/version-(\d+\.\d+\.\d+)-/ },
{ file: 'skills/okr-offentlig-sektor/SKILL.md', re: /^version:\s*"?([^"\s]+)"?\s*$/m },
{ file: 'skills/okr-second-brain-search/SKILL.md', re: /^version:\s*"?([^"\s]+)"?\s*$/m },
];
test('versjonssync: alle shippede flater baerer package.json-versjonen', () => {
const expected = readPkg().version;
const drift = [];
for (const { file, re } of VERSION_SURFACES) {
const m = re.exec(readFileSync(join(ROOT, file), 'utf8'));
if (!m) {
drift.push(`${file}: fant ingen versjon (flaten flyttet? oppdater regexen)`);
continue;
}
if (m[1] !== expected) drift.push(`${file}: ${m[1]} != ${expected}`);
}
assert.deepEqual(drift, [], `delvis versjonsbump (forventet ${expected}):\n${drift.join('\n')}`);
});