test(okr): generiske, fiktive fixturer og testdata

okf-realistic har samme struktur og samme tall som før. Organisasjonen er
Fjordvik kommune (fiktiv), og OKR-fila heter okr-vannforsyning.md, så den
alfabetiske rekkefølgen mot okr-digitalisering.md holder. KR2 går fra 12
til 20 med nå-verdi 17, og scoren er fortsatt 0.625. Retrieval-testene
bruker fortsatt «nullvisjon», og disambigueringen bruker et felles token i
tittel og status-kropp, så de tester det samme på nytt innhold.
docx-fixturen er bygget på nytt med bare document.xml endret. Øvrige
testdata (KR-navn, sektorverdi, eksempeltekst) er nøytrale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-23 12:27:22 +02:00
commit 6712f855ed
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
17 changed files with 61 additions and 61 deletions

View file

@ -103,7 +103,7 @@ test('at-risk telles per status-RAD (tabell), ikke raaforekomster i prosa (B2/M1
'',
'| KR | Baseline | Maal | Naa | Score | Status |',
'|----|----------|------|-----|-------|--------|',
'| KR1: Redusere ulykker | 40 | 30 | 35 | 0.50 | I fare |',
'| KR1: Redusere lekkasjer | 40 | 30 | 35 | 0.50 | I fare |',
'| KR2: Oppetid | 10 | 25 | 22 | 0.80 | Paa sporet |',
'| KR3: Tilfredshet | 60% | 90% | 65% | 0.17 | Blokkert |',
'',
@ -134,8 +134,8 @@ test('at-risk telles paa kanonisk 1.8.0-vokabular (At Risk + Off Track, ikke On
'',
'| KR | Baseline | Target | Naa | Score | Status |',
'|----|----------|--------|-----|-------|--------|',
`| KR1: Redusere ulykker | 40 | 30 | 35 | 0.50 | At Risk ${GUL} |`,
`| KR2: Fartshumper installert | 0% | 100% | 60% | 0.60 | On Track ${GROENN} |`,
`| KR1: Redusere lekkasjer | 40 | 30 | 35 | 0.50 | At Risk ${GUL} |`,
`| KR2: Hoeydebasseng sikret | 0% | 100% | 60% | 0.60 | On Track ${GROENN} |`,
`| KR3: Foreldre-tilfredshet | 60% | 90% | 65% | 0.17 | Off Track ${ROED} |`,
'',
].join('\n'));
@ -181,12 +181,12 @@ const GENERERT_HODE = [
function generertStatus({ committed = [], aspirational = [] }) {
const ut = ['# Statusrapport T2-2026', ''];
if (committed.length > 0) {
ut.push('## Committed Key Results', '', '### Trafikksikkerhet', '', ...GENERERT_HODE.slice(2), ...committed, '');
ut.push('## Committed Key Results', '', '### Forsyningssikkerhet', '', ...GENERERT_HODE.slice(2), ...committed, '');
}
ut.push(
'## Avvik som skal forklares',
'',
'- Trafikksikkerhet: KR1 -- naa 17 mot krav 20 (score 0.63)',
'- Forsyningssikkerhet: KR1 -- naa 17 mot krav 20 (score 0.63)',
'',
);
if (aspirational.length > 0) {
@ -261,7 +261,7 @@ test('fallback: rader uten seksjonsoverskrift telles som committed, ikke bortfil
'# Status T2-2026',
'',
...GENERERT_HODE.slice(2),
'| KR1: Redusere ulykker | 40 | 30 | 35 | 0.50 | Ja | At Risk |',
'| KR1: Redusere lekkasjer | 40 | 30 | 35 | 0.50 | Ja | At Risk |',
'| KR2: Oppetid | 10 | 25 | 22 | 0.80 | Nei | On Track |',
'| KR3: Tilfredshet | 60 | 90 | 65 | 0.17 | Ja | At Risk |',
'',

Binary file not shown.

View file

@ -1,4 +1,4 @@
# OKF second brain - Vegdirektoratet (realistisk testfixtur)
# OKF second brain - Fjordvik kommune (realistisk testfixtur)
okf_version: 0.1
okf_layout: kb-layout-2026-06

View file

@ -2,4 +2,4 @@
* [Tildelingsbrev 2026](tildelingsbrev-2026.md) - Klimaomstilling og sikkerhet.
* [Virksomhetsplan 2026](virksomhetsplan.md) - Kompetanseloeft og effektivisering.
* [Organisasjonsprofil](organisasjonsprofil.md) - Vegdirektoratet, offentlig sektor.
* [Organisasjonsprofil](organisasjonsprofil.md) - Fjordvik kommune, offentlig sektor.

View file

@ -9,4 +9,4 @@ timestamp: '2026-01-05T08:00:00+00:00'
---
# Organisasjonsprofil
Organisasjonen er Vegdirektoratet, en etat i offentlig sektor.
Organisasjonen er Fjordvik kommune, en fiktiv kommune i offentlig sektor.

View file

@ -10,4 +10,4 @@ timestamp: '2026-01-15T09:00:00+00:00'
---
# Tildelingsbrev 2026
Hovedprioriteten for 2026 er klimaomstilling i transportsektoren.
Hovedprioriteten for 2026 er klimaomstilling i vann- og avloepstjenestene.

View file

@ -1,5 +1,5 @@
# Syklus T1-2026
* [Trafikksikkerhet og tunnelsikkerhet](okr-trafikksikkerhet.md) - Maal om nullvisjon i tunneler.
* [Forsyningssikkerhet for drikkevann](okr-vannforsyning.md) - Maal om nullvisjon for driftsavbrudd.
* [Digitalisering av tjenester](okr-digitalisering.md) - Oekt selvbetjeningsgrad.
* [Statusrapport T1](status.md) - Fremdriftsindikator for tertialet.

View file

@ -1,31 +0,0 @@
---
type: OKR
resource: local
title: Trafikksikkerhet og tunnelsikkerhet
description: Tertialmaal for sikrere veier og tunneler.
tags:
- sikkerhet
- tunnel
timestamp: '2026-02-01T09:00:00+00:00'
kr1_navn: Alvorlige tunnelhendelser (antall)
kr1_baseline: 0
kr1_target: 0
kr1_naa: 0
kr1_type: committed
kr2_navn: Tunneler med oppgradert sikkerhetsutrustning (antall)
kr2_baseline: 12
kr2_target: 20
kr2_naa: 17
kr2_type: committed
---
# Trafikksikkerhet og tunnelsikkerhet
Objective: Styrke tunnelsikkerhet i tertialet.
KR1: Naa nullvisjon for alvorlige tunnelhendelser.
- Maalemetode: Registrerte alvorlige hendelser i hendelsesdatabasen.
- Datakilde: Vegtrafikksentralen.
- Type: Committed
KR2: Oeke antall tunneler med oppgradert sikkerhetsutrustning fra 12 til 20.
- Maalemetode: Telling av ferdigattesterte tunneler.
- Datakilde: Prosjektportefoeljen.
- Type: Committed

View file

@ -0,0 +1,31 @@
---
type: OKR
resource: local
title: Forsyningssikkerhet for drikkevann
description: Tertialmaal for sikrere vannforsyning og hoeydebasseng.
tags:
- sikkerhet
- vann
timestamp: '2026-02-01T09:00:00+00:00'
kr1_navn: Alvorlige driftsavbrudd i vannforsyningen (antall)
kr1_baseline: 0
kr1_target: 0
kr1_naa: 0
kr1_type: committed
kr2_navn: Hoeydebasseng med oppgradert sikringsutstyr (antall)
kr2_baseline: 12
kr2_target: 20
kr2_naa: 17
kr2_type: committed
---
# Forsyningssikkerhet for drikkevann
Objective: Styrke forsyningssikkerhet i tertialet.
KR1: Naa nullvisjon for alvorlige driftsavbrudd.
- Maalemetode: Registrerte alvorlige avbrudd i driftsloggen.
- Datakilde: Driftssentralen for vann og avloep.
- Type: Committed
KR2: Oeke antall hoeydebasseng med oppgradert sikringsutstyr fra 12 til 20.
- Maalemetode: Telling av ferdigattesterte hoeydebasseng.
- Datakilde: Prosjektportefoeljen.
- Type: Committed

View file

@ -9,4 +9,4 @@ timestamp: '2026-04-30T16:00:00+00:00'
---
# Statusrapport T1-2026
Fremdriftsindikator viser god progresjon. Arbeidet med tunnelsikkerhet ligger noe bak skjema.
Fremdriftsindikator viser god progresjon. Arbeidet med forsyningssikkerhet ligger noe bak skjema.

View file

@ -31,7 +31,7 @@ function makeFullConfig(workDir, fields = {}) {
navn: 'TestOrg',
kortform: 'TO',
gjeldende: 'T2-2026',
sektor: 'transport',
sektor: 'kommune',
modenhetsnivaa: 'nivaa-2',
fase: 'utforsker',
okr_frikoblet_fra_loenn: 'true',
@ -88,7 +88,7 @@ test('full config: alle 9 noekler resolver likt som foer', () => {
const out = runHook(work, home);
assert.match(out, /Organisasjon: TestOrg \(TO\)/, 'navn + kortform');
assert.match(out, /Syklus: T2-2026 \[utforsker\]/, 'gjeldende + fase');
assert.match(out, /Sektor: transport/, 'sektor');
assert.match(out, /Sektor: kommune/, 'sektor');
assert.match(out, /Modenhet: nivaa-2/, 'modenhetsnivaa');
assert.match(out, /OKR frikoblet fra lonn: true/, 'frikoblet-verdi');
assert.match(out, /Psykologisk trygghet: hoy/, 'psykologisk_trygghet');

View file

@ -30,7 +30,7 @@ function makeProjectConfig(work, navn = 'CapTestOrg') {
mkdirSync(p, { recursive: true });
writeFileSync(
join(p, 'okr.local.md'),
`---\nnavn: "${navn}"\ngjeldende: "T1-2026"\nsektor: "transport"\n---\n`,
`---\nnavn: "${navn}"\ngjeldende: "T1-2026"\nsektor: "kommune"\n---\n`,
);
}

View file

@ -53,7 +53,7 @@ function withBundle(fn) {
}
}
const TILDELING = '# Tildelingsbrev 2026\n\nStatens vegvesen skal levere paa foelgende maal i 2026.\n';
const TILDELING = '# Tildelingsbrev 2026\n\nFjordvik kommune skal levere paa foelgende maal i 2026.\n';
const MERKNAD = '# Generell merknad\n\nEt fritt notat uten foeringsord i tittel.\n';
test('writeConcepts: type->nivaa-ruting (strategisk-kontekst + dokumenter)', () => {

View file

@ -89,9 +89,9 @@ test('brukerverdi: token-tabell resolver hver til forventet konsept (okf-realist
const table = [
{ token: 'klimaomstilling', expect: 'strategisk-kontekst/tildelingsbrev-2026.md' },
{ token: 'kompetanseloeft', expect: 'strategisk-kontekst/virksomhetsplan.md' },
{ token: 'Vegdirektoratet', expect: 'strategisk-kontekst/organisasjonsprofil.md' },
{ token: 'Fjordvik', expect: 'strategisk-kontekst/organisasjonsprofil.md' },
{ token: 'selvbetjeningsgrad', expect: 'syklus/T1-2026/okr-digitalisering.md' },
{ token: 'nullvisjon', expect: 'syklus/T1-2026/okr-trafikksikkerhet.md' },
{ token: 'nullvisjon', expect: 'syklus/T1-2026/okr-vannforsyning.md' },
{ token: 'fremdriftsindikator', expect: 'syklus/T1-2026/status.md' },
{ token: 'laeringssloeyfe', expect: 'historikk/retrospektiv-T3-2025.md' },
{ token: 'arbeidsnotat', expect: 'dokumenter/notat.md' },
@ -106,9 +106,9 @@ test('brukerverdi: token-tabell resolver hver til forventet konsept (okf-realist
// (c) DISAMBIGUERING (Pass 2): delt token mellom 2 filer -> index.md-routing/ranking
// velger riktig topp-treff (frontmatter+index-entry tie-break).
test('disambiguering: delt token rangerer frontmatter/index-treff over body-treff', () => {
const hits = retrieve(REALISTIC, 'tunnelsikkerhet');
const hits = retrieve(REALISTIC, 'forsyningssikkerhet');
assert.equal(hits.length, 2, 'delt token skal treffe begge filer');
assert.equal(rel(REALISTIC, hits[0].path), 'syklus/T1-2026/okr-trafikksikkerhet.md',
assert.equal(rel(REALISTIC, hits[0].path), 'syklus/T1-2026/okr-vannforsyning.md',
'frontmatter+index-entry-treff skal rangeres over body-only-treff');
assert.equal(rel(REALISTIC, hits[1].path), 'syklus/T1-2026/status.md');
assert.ok(hits[0].score > hits[1].score, 'topp-treff skal ha hoyere score (deterministisk tie-break)');

View file

@ -21,7 +21,7 @@ import { fileURLToPath } from 'node:url';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const SYKLUS = 'tests/fixtures/okf-realistic/syklus/T1-2026';
const OKR_FILER = ['okr-trafikksikkerhet.md', 'okr-digitalisering.md'];
const OKR_FILER = ['okr-vannforsyning.md', 'okr-digitalisering.md'];
const lesFixture = (navn) => readFileSync(join(ROOT, SYKLUS, navn), 'utf8');
@ -87,7 +87,7 @@ test('(B1) lesSyklus leser begge OKR-filene med KR-ene sine', () => {
// arver denne rekkefolgen, saa den er del av kontrakten, ikke en tilfeldighet.
assert.deepEqual(
syklus.okrer.map((o) => o.fil),
['okr-digitalisering.md', 'okr-trafikksikkerhet.md'],
['okr-digitalisering.md', 'okr-vannforsyning.md'],
);
const digi = syklus.okrer[0];
assert.equal(digi.tittel, 'Digitalisering av tjenester');
@ -114,7 +114,7 @@ test('(B2) lesSyklus tolker tallene som tall, ikke strenger', () => {
});
test('(B3) beregnScore: kanonisk formel paa et kjent KR-par', () => {
// Tunneler oppgradert: (17 - 12) / (20 - 12) = 0.625
// Hoeydebasseng oppgradert: (17 - 12) / (20 - 12) = 0.625
assert.equal(beregnScore({ baseline: 12, target: 20, naa: 17 }), 0.625);
});

View file

@ -85,10 +85,10 @@ test('(2a) invariant 1: typen er merket i rapporteringen', () => {
test('(2b) invariant 2: committed rapporteres binaert mot kravet', () => {
const md = rapport();
// Avvik-kolonnen finnes, og tunnel-KR2 (17 av 20) er et avvik selv om
// Avvik-kolonnen finnes, og hoeydebasseng-KR2 (17 av 20) er et avvik selv om
// scoren er 0.63 -- et krav er naadd eller ikke.
assert.match(md, /\|\s*Avvik\s*\|/, 'mangler Avvik-kolonne for committed');
const rad = md.split('\n').find((l) => l.includes('oppgradert sikkerhetsutrustning'));
const rad = md.split('\n').find((l) => l.includes('oppgradert sikringsutstyr'));
assert.ok(rad, 'fant ikke committed-KR-raden');
assert.match(rad, /\|\s*Ja\s*\|/, 'committed under target maa merkes som avvik');
});
@ -203,7 +203,7 @@ test('(8a) del III bygger paa aarsrapportens eget anker og en seksjon per Object
assert.match(md, /[Aa]arets aktiviteter og resultater/, 'del III-ankeret mangler');
const objectives = md.split('\n').filter((l) => /^##\s+(?!Flerarig|Aspirational|Avvik)/.test(l));
assert.equal(objectives.length, 2, `forventet 2 Objective-seksjoner, fant ${objectives.length}`);
assert.match(md, /Trafikksikkerhet og tunnelsikkerhet/);
assert.match(md, /Forsyningssikkerhet for drikkevann/);
assert.match(md, /Digitalisering av tjenester/);
});
@ -290,7 +290,7 @@ test('(9c) styringsparametere kobles mot tildelingsbrevet, og oppfinnes ikke', (
// Generatoren leser ikke tildelingsbrevet -- den har bare syklusdataene. Da er
// koblingen et felt den RESERVERER, aldri et den fyller. Hvert Objective staar
// i tabellen; kravet ved siden av er tomt.
assert.match(kropp, /Trafikksikkerhet og tunnelsikkerhet/);
assert.match(kropp, /Forsyningssikkerhet for drikkevann/);
assert.match(kropp, /Digitalisering av tjenester/);
assert.match(kropp, /[Ff]ylles ut/, 'koblingen maa vaere merket som utfylles av virksomheten');
});
@ -327,7 +327,7 @@ function avvikKropp(md) {
}
// Fixturens KR-er, med de rollene steg 7 ga dem.
const COMMITTED_UNDER_KRAV = 'Tunneler med oppgradert sikkerhetsutrustning';
const COMMITTED_UNDER_KRAV = 'Hoeydebasseng med oppgradert sikringsutstyr';
const ASPIRATIONAL_LAV_SCORE = ['Andel digitale soeknader', 'Gjennomsnittlig saksbehandlingstid'];
for (const [navn, bygger] of FORMER) {

View file

@ -47,8 +47,8 @@ function lagSyklus(t) {
}
const FULL = {
'Alvorlige tunnelhendelser (antall)': 'Off Track',
'Tunneler med oppgradert sikkerhetsutrustning (antall)': 'At Risk',
'Alvorlige driftsavbrudd i vannforsyningen (antall)': 'Off Track',
'Hoeydebasseng med oppgradert sikringsutstyr (antall)': 'At Risk',
'Andel digitale soeknader (prosent)': 'At Risk',
'Gjennomsnittlig saksbehandlingstid (dager)': 'On Track',
};