okr/tests/package-shape.test.mjs
Kjell Tore Guttormsen 37142236f2 feat(okr): 1.8.0 En kanon versjonssync + CHANGELOG
Step 14 (Wave 6), siste steg i fase C3. Alle versjonsflater 1.7.1 -> 1.8.0:
plugin.json:3, package.json:3, package-lock.json:3+9, CLAUDE.md:1, README.md
badge, SKILL.md x2. Ny Keep-a-Changelog-seksjon [1.8.0] + README-historikkrad
som oppsummerer F-a..F-i, score-grenser, konsistensvakten og C6-markeds-
oppdateringen fra Steps 1-13.

TDD: package.json bumpet foerst -> package-shape.test.mjs case 1 gikk ROED
(expected 1.7.1, actual 1.8.0) -> assertion + header-kommentar oppdatert til
1.8.0 (minor-lane C: En kanon) -> GROENN. Historiske "B1/B2 (1.7.1)"-
provenanskommentarer i tester og historikkrader for 1.7.1 er urort.

To presisjonsfikser tatt inn fra S31-funn (begge i filer Step 14 allerede rorer):
- CLAUDE.md:21 sa "score the 16 domain reference files". Fasit: 16 AV 17 scores;
  okr-quality-rubrics.md er ekskludert (sirkulaer - den er selv scorings-
  instrumentet). Skrevet i samme presise form som README:150.
- CLAUDE.md:73 pekte paa lib/innboks-convert.mjs. Modulen har ALDRI eksistert
  (git log --all paa stien: tom; adapterne har ligget i lib/convert/ siden
  a807ee2). Rettet til lib/convert/index.mjs. Samme feilsti stod i CHANGELOG
  1.7.0-noten (linje 34) og er rettet der ogsaa: en dokumentert modul som aldri
  fantes er en usann paastand, ikke historisk provenans.

CHANGELOG-datoen er satt til 2026-07-25 (i dag). Faller C7-releasen paa en
senere dato, maa datoen justeres da.

Verify: node --test --test-reporter=tap tests/*.test.mjs -> 163 pass / 0 fail.
grep -rc "1.7.1" plugin.json package.json CLAUDE.md -> 0/0/0.
9 filer endret = Manifest expected_paths 1:1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016pUfkQ1YyH75z9y6RBaBHG
2026-07-25 06:44:35 +02:00

69 lines
2.7 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.8.0 (minor-lane C: En kanon), 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.8.0 (minor-lane)', () => {
const pkg = readPkg();
assert.equal(pkg.type, 'module');
assert.equal(pkg.version, '1.8.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}`);
}
});