feat(okr): KR-datakontrakt i skriv-malen
This commit is contained in:
parent
2c42e422c1
commit
e3a99b02ff
2 changed files with 84 additions and 0 deletions
|
|
@ -104,6 +104,54 @@ KR[n]: [Formulering med baseline → target]
|
||||||
- Type: Committed / Aspirational
|
- Type: Committed / Aspirational
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Maskinlaget: KR-datakontrakten i frontmatter
|
||||||
|
|
||||||
|
Punktprosaen over er for mennesker og beholdes uendret. Ved siden av den legges
|
||||||
|
**samme tall som maskinlesbar frontmatter** i `okr-*.md`, slik at rapport-
|
||||||
|
generatorene (`/okr:rapport`) kan lese syklusen uten å tolke prosa.
|
||||||
|
|
||||||
|
Emitter fem nøkler per KR `n`, nummerert fra 1:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
type: OKR
|
||||||
|
kr1_navn: Saksbehandlingstid førerkort (dager)
|
||||||
|
kr1_baseline: 14
|
||||||
|
kr1_target: 5
|
||||||
|
kr1_naa: 11
|
||||||
|
kr1_type: committed
|
||||||
|
kr2_navn: Andel digitale søknader (%)
|
||||||
|
kr2_baseline: 60
|
||||||
|
kr2_target: 85
|
||||||
|
kr2_naa: 72
|
||||||
|
kr2_type: aspirational
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
| Nøkkel | Innhold |
|
||||||
|
|--------|---------|
|
||||||
|
| `krN_navn` | Tekst. Kortform av KR-en. **Enheten hører hjemme her** (og i prosaen) |
|
||||||
|
| `krN_baseline` | Utgangspunktet ved syklusstart |
|
||||||
|
| `krN_target` | Målverdien ved syklusslutt |
|
||||||
|
| `krN_naa` | Nåverdien. **Oppdateres ved hver check-in** |
|
||||||
|
| `krN_type` | `committed` eller `aspirational` — små bokstaver |
|
||||||
|
|
||||||
|
**Tre regler som gjør kontrakten lesbar for generatoren:**
|
||||||
|
|
||||||
|
1. **Rene tall uten enhet.** `kr1_baseline: 14`, aldri `14 dager` eller `60 %`.
|
||||||
|
Enheten bæres av `krN_navn` og av prosaen — et tall med enhet er ikke et tall.
|
||||||
|
2. **Score skrives aldri til fil.** Den beregnes av generatoren som
|
||||||
|
`(nåværende − baseline) / (target − baseline)`. En lagret score er en andre
|
||||||
|
sannhetskilde som drifter fra tallene den ble utledet av. Ingen `krN_score`.
|
||||||
|
3. **Nedadgående mål trenger ingen særbehandling** — `baseline: 14, target: 5`
|
||||||
|
fungerer som-er, fordi teller og nevner begge blir negative.
|
||||||
|
|
||||||
|
For binære KR (milepæl): sett `krN_baseline: 0` og `krN_target: 1`, og la
|
||||||
|
`krN_naa` være `0` eller `1`.
|
||||||
|
|
||||||
|
`/okr:skriv` skriver ikke til disk. Emitter frontmatteren sammen med OKR-teksten
|
||||||
|
og be brukeren lagre den i `.claude/okr/syklus/[syklus-id]/okr-[navn].md`.
|
||||||
|
|
||||||
## Strategi-til-OKR
|
## Strategi-til-OKR
|
||||||
|
|
||||||
Når brukeren har strategidokument eller tildelingsbrev som input:
|
Når brukeren har strategidokument eller tildelingsbrev som input:
|
||||||
|
|
|
||||||
|
|
@ -511,3 +511,39 @@ test('(m2) D4: kommunal-styring siterer ikke DFO-notat 2026:2 (sektoravgrensning
|
||||||
'DFO-notat 2026:2 er avgrenset mot kommunal sektor og kan ikke siteres her',
|
'DFO-notat 2026:2 er avgrenset mot kommunal sektor og kan ikke siteres her',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- (n) D5 steg 6: KR-datakontrakten (beslutning B-1) er dokumentert i skriv-malen ---
|
||||||
|
// Generatorene i lib/syklus-*.mjs leser KR-tall fra `krN_`-noekler i okr-*.md sin
|
||||||
|
// frontmatter. Kontrakten har ingen skjema-fil aa haandheve seg mot -- den haandheves
|
||||||
|
// av at DEFINISJONSFLATEN (skriv-malen) dokumenterer den, siden /okr:skriv er stedet
|
||||||
|
// tallene oppstaar. Vakten binder de to sidene sammen: endres kontrakten i lib/ uten
|
||||||
|
// at malen foelger etter, produserer brukeren filer generatoren ikke kan lese.
|
||||||
|
const KR_KONTRAKT_NOEKLER = ['navn', 'baseline', 'target', 'naa', 'type'];
|
||||||
|
|
||||||
|
test('(n) D5: skriv.md dokumenterer alle fem krN_-noeklene i KR-datakontrakten', () => {
|
||||||
|
const doc = readDoc('commands/skriv.md');
|
||||||
|
const missing = KR_KONTRAKT_NOEKLER.filter(
|
||||||
|
(k) => !new RegExp(`kr(?:N|\\d+)_${k}\\b`).test(doc),
|
||||||
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
missing,
|
||||||
|
[],
|
||||||
|
`KR-datakontrakten (B-1) mangler noekler i commands/skriv.md: ${missing.join(', ')}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// B-2: score BEREGNES, lagres aldri. En `krN_score`-noekkel i malen ville skapt en
|
||||||
|
// andre sannhetskilde som kan drifte fra (naa - baseline) / (target - baseline).
|
||||||
|
// Fravaers-invariant paa NOEKKELFORMEN slik lib/frontmatter.mjs:29 leser den
|
||||||
|
// (`^\s*key:`) -- ikke paa ordet "score", som malen legitimt bruker om
|
||||||
|
// moonshot/roofshot-kalibrering (:124), og ikke paa prosa som FORBYR noekkelen.
|
||||||
|
// Det er noekkelen i frontmatter som skaper den andre sannhetskilden; en omtale
|
||||||
|
// av den gjoer det ikke.
|
||||||
|
test('(n2) D5: skriv.md introduserer ingen krN_score-noekkel (score lagres aldri)', () => {
|
||||||
|
const offenders = linesMatching(readDoc('commands/skriv.md'), /^\s*kr(?:N|\d+)_score\s*:/m);
|
||||||
|
assert.deepEqual(
|
||||||
|
offenders,
|
||||||
|
[],
|
||||||
|
'score skal beregnes fra baseline/target/naa, aldri lagres som egen noekkel',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue