Lukker de fire release-relevante MAJOR-funnene fra /trekreview (S33). Alle TDD
roed -> groenn, ingen fiks landet uten en test som feilet foerst. Suite 163 -> 167.
R1 (af16d5e4) hooks/scripts/coaching-hook.mjs:83 -- LEVENDE REGRESJON innfoert av
1.8.0. Denne releasen skrev status-malen (commands/sporing.md:86-88) om til den
kanoniske skalaen On Track/At Risk/Off Track, mens hooken fortsatt talte kun
/i fare|blokkert/i over tabellrader. En status generert under 1.8.0 ga derfor
atRiskCount = 0 og SessionStart-nudgen sluttet stille aa utloese seg. Hooken
teller naa de kanoniske etikettene; de to norske er BEHOLDT som bakover-
kompatibilitet for status-filer skrevet foer 1.8.0. Nudge-teksten bruker samme
kanoniske vokabular. Ny testcase mates av malen slik den faktisk genereres i dag;
den eksisterende casen beholder gammelt vokabular og daekker legacy-stien.
R2 (7ec575be) F-i-omskrivingen ga hver kommando en Kontekstbevissthet-blokk som
INSTRUERER Glob, men allowed-tools ble kun utvidet i kaskade.md. Glob lagt til i
export, gap, governance, innfoering, kvalitet, moeter, skriv, sporing. Ny vakt-
case (k): nevner BODY verktoeyet, maa frontmatter deklarere det (13 kommandoer
instruerer Glob; alle 13 dekket). Case (i) grepper kun etter fjernede fraser og
kunne ikke fange dette.
R3 (5e61ae0d) tests/package-shape.test.mjs asserterte KUN package.json -- som er
private:true og dermed den ene flaten som aldri shipper. En delvis bump ville
shippet groenn. Ny versjonssync-case dekker .claude-plugin/plugin.json, README-
badgen og begge SKILL.md, med forventet verdi UTLEDET fra package.json (ett sted
aa endre ved neste bump). Mutasjonsbevist: hver av de fire flatene tilbakestilt
til 1.7.1 en om gangen -> casen roed i alle fire tilfeller.
R4 (ccff16e1 + 231c53fc) Tre parallelle confidence-etikettsett overlevde F-c:
fremdriftssporer-agent.md:68 ("Paa sporet / I fare / Blokkert"), :98
("Confidence: [Hoey/Medium/Lav]" -- en annen akse: stoerrelse, ikke sannsynlighet)
og SKILL.md:48 ("blocked"; kanonisk er "off track"). Alle tre erstattet med
referanse til kanon (okr-framework.md:389-392). sporing.md og agenten den
delegerer til svarer naa i samme vokabular. Vakt-case (a)/(b) skanner naa samme
sett som (d) allerede brukte (+ agents/ + SKILL.md), samlet i canonScan(). Ny
case (a2) fanger etikettsett skrevet som bullet eller mal-linje -- tabell-
signaturen alene fanget dem ikke, og det var nettopp formen driften overlevde i.
Divergens gjenkjennes STRUKTURELT (skraastrek-enumerasjon av >= 2 etiketter, med
>= 1 ikke-kanonisk), saa loepende prosa som "For KR i fare" og "Blokkert av
eksterne faktorer" ikke gir falske positive. Verifisert: roed-listen var noeyaktig
de 3 kjente linjene, ingen andre.
CHANGELOG/README: vakt-antall 13 -> 15 cases, suite 149 -> 167, og de fire
fiksene lagt inn under [1.8.0] (Added + Fixed). Ingen versjonsbump.
GJENSTAAR fra reviewet (3 MAJOR, IKKE i denne bolgen): 607313e3 F-d-kadens-
moensteret kan ikke feile paa den kanoniske kadens-tabellen; 029ef814
freshen-references.md:24 baerer fortsatt en foreldet kontekstblokk og vaktens
exclude-kommentar kaller fila feilaktig "allerede-fikset" (den er utenfor
1.8.0-scope by design, jf. ba91fc2 -- kommentaren er usann, ikke ekskluderingen);
7579d59c "Outcome" er utestbar i 10-dims-casen pga. substring-containment.
Verify: node --test --test-reporter=tap tests/*.test.mjs -> 167 pass / 0 fail.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016pUfkQ1YyH75z9y6RBaBHG
94 lines
3.9 KiB
JavaScript
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.8.0 (minor-lane C: En kanon) 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.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}`);
|
|
}
|
|
});
|
|
|
|
// 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')}`);
|
|
});
|