Lukker discovery-løkken gjennom operatør-gaten. data/decisions.json er eneste skrive-autoriserte bro mellom deteksjon og KB/registry; discovery LESER den og utelater alt operatøren har tatt stilling til. Dedup-policy = A (operatør-valg): isDecided = enhver ledger-entry (approved/ rejected/pending). Kun helt fraværende URLer re-foreslås. - lib/decisions-io.mjs: createLedger/load/save(atomisk)/isDecided/recordDecision (ren)/filterUndecided. TDD: 10 tester før kode. - discover-new-urls.mjs leser ledger, filtrerer, rapporterer deduped_by_ledger. Importerer ALDRI write-utils (invariant verifisert, 6 guard-tester). - Gate dokumentert i kb-update.md §3b (eneste skrivevei). - decisions.json tracket via gitignore-negasjon (som domain-taxonomy.json). Kriterium møtt: dedup-diff (rejected re-foreslås ikke runde 2). Tester: validate 239 · kb-update 82 (+16) · kb-eval 13 · kb-integrity 115/115. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01REiKFhP4w6xGXXqWKpPCJJ
44 lines
1.8 KiB
JavaScript
44 lines
1.8 KiB
JavaScript
// tests/kb-update/test-discover-invariant.test.mjs
|
|
// Architecture-invariant guard (STATE.md §83 / roadmap §159): the detection
|
|
// script discover-new-urls.mjs must NEVER import write-utils. It only READS the
|
|
// decision ledger to filter; all writes go through the operator gate. saveReport
|
|
// (its own discovery-report.json) is allowed — that is detection's own output,
|
|
// not a KB/registry mutation.
|
|
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const DISCOVER = join(__dirname, '..', '..', 'scripts', 'kb-update', 'discover-new-urls.mjs');
|
|
const src = readFileSync(DISCOVER, 'utf8');
|
|
|
|
// Sjekkene er IMPORT-spesifikke med vilje: en invariant-guard som brytes av en
|
|
// kommentar som *beskriver* invarianten er verdiløs. Vi gransker import-linjer.
|
|
const importLines = src.split('\n').filter((l) => /^\s*import\b/.test(l)).join('\n');
|
|
|
|
test('discover does NOT import the ledger write path (saveDecisions)', () => {
|
|
assert.doesNotMatch(importLines, /\bsaveDecisions\b/);
|
|
});
|
|
|
|
test('discover does NOT import the registry write path (saveRegistry)', () => {
|
|
assert.doesNotMatch(importLines, /\bsaveRegistry\b/);
|
|
});
|
|
|
|
test('discover does NOT import atomic-write', () => {
|
|
assert.doesNotMatch(importLines, /from\s+'[^']*atomic-write[^']*'/);
|
|
});
|
|
|
|
test('discover does NOT import backup', () => {
|
|
assert.doesNotMatch(importLines, /from\s+'[^']*\/backup\.mjs'/);
|
|
});
|
|
|
|
test('discover DOES read the ledger (loadDecisions from decisions-io)', () => {
|
|
assert.match(src, /import \{[^}]*\bloadDecisions\b[^}]*\} from '\.\/lib\/decisions-io\.mjs'/);
|
|
});
|
|
|
|
test('discover actually applies the dedup filter (isDecided)', () => {
|
|
assert.match(src, /isDecided\(/);
|
|
});
|