feat(okr): arkivklar-kommando og GDPR-posisjon i governance

This commit is contained in:
Kjell Tore Guttormsen 2026-08-02 10:27:32 +02:00
commit 42d75dfad8
6 changed files with 265 additions and 7 deletions

View file

@ -290,3 +290,76 @@ test('(18i) CLI skriver rapport atomisk til oppgitt fil, uten aa roere bundlen',
);
});
});
// ==================== (19) kommandoflaten og registrering ====================
const ROOT = fileURLToPath(new URL('..', import.meta.url));
const les = (rel) => readFileSync(join(ROOT, rel), 'utf8');
// Presedens: commands/sporing.md:4 -- en kommando uten skriveverktoey KAN ikke
// skrive, uansett hva prosaen lover. Tool-lista er den haandhevbare grensen;
// prosaen er det ikke. /okr:arkivklar er raadgivende og skal aldri kunne endre
// treet den vurderer.
const SKRIVEVERKTOEY = ['Write', 'Edit', 'NotebookEdit', 'MultiEdit'];
function allowedTools(rel) {
const m = les(rel).match(/^allowed-tools:\s*(.+)$/m);
assert.ok(m, `${rel}: mangler allowed-tools i frontmatter`);
return m[1].split(',').map((t) => t.trim());
}
test('(19a) arkivklar-kommandoen deklarerer ingen skriveverktoey', () => {
const tools = allowedTools('commands/arkivklar.md');
const forbudte = tools.filter((t) => SKRIVEVERKTOEY.includes(t));
assert.deepEqual(
forbudte,
[],
`/okr:arkivklar er lesende og skal ikke ha skriveverktoey; fant: ${forbudte.join(', ')}`,
);
assert.ok(tools.includes('Read'), 'kommandoen trenger Read');
assert.ok(tools.includes('Bash'), 'kommandoen trenger Bash for aa kjoere skriptet');
});
test('(19b) parser-sanity: vakten feiler faktisk om et skriveverktoey legges til', () => {
// Uten denne beviser (19a) bare at lista ikke inneholder noe -- den kunne
// bestaatt paa en tom/uparset liste. Her mates vakten en liste som SKAL felle.
const mutant = ['Read', 'Bash', 'Glob', 'Write'];
assert.deepEqual(
mutant.filter((t) => SKRIVEVERKTOEY.includes(t)),
['Write'],
'vakten skal fange Write om det legges til',
);
});
test('(19c) arkivklar er registrert paa alle kommandoflater', () => {
// D6-beslutning 7: en levert form skal synes paa ALLE flater samtidig.
// Sjekklista er commands/<navn>.md, commands/help.md, CLAUDE.md, README.md --
// help.md og README.md var nettopp de to som ble oversett i steg 12.
const mangler = [];
for (const f of ['CLAUDE.md', 'README.md', 'commands/help.md']) {
if (!/okr:arkivklar/.test(les(f))) mangler.push(f);
}
assert.deepEqual(mangler, [], `/okr:arkivklar mangler paa flate(r):\n${mangler.join('\n')}`);
});
test('(19d) GDPR-posisjonen staar i governance og ender paa «behold, men skjerm»', () => {
const gov = les('skills/okr-offentlig-sektor/references/okr-offentlig-governance.md');
for (const forventet of [
'klart fastsett', // arkivlova § 13 tredje punktum, ordrett
'andre måtar enn ved kassasjon',
'17 nr. 3', // GDPR art. 17 nr. 3 b og d
'LOV-2025-06-20-96',
'FOR-2025-12-19-2729',
'Nasjonalarkivet',
]) {
assert.ok(gov.includes(forventet), `governance mangler «${forventet}»`);
}
assert.ok(/sperrer|skjerm/i.test(gov), 'posisjonen skal formuleres som «sletter ikke, sperrer»');
// Datatilsynets vedtakskompetanse er KUN DELVIS verifisert (403 paa
// Nasjonalarkivets side). Den skal derfor ikke siteres med paragrafnummer.
assert.ok(
!/Datatilsynet[^.]{0,80}§\s*\d/.test(gov),
'Datatilsynets vedtakskompetanse skal ikke siteres med paragrafnummer (kun delvis verifisert)',
);
});