fix(okr): separer committed og aspirational i sporings-malene

This commit is contained in:
Kjell Tore Guttormsen 2026-08-02 07:01:55 +02:00
commit 785385baa3
3 changed files with 97 additions and 18 deletions

View file

@ -61,7 +61,10 @@ Score = (Nåværende - Baseline) / (Target - Baseline)
2. **Beregn score**:
- Per KR
- Samlet (vektet gjennomsnitt)
- Oppsummert **per type**, aldri som ett felles tall: committed rapporteres som
hvor mange KR som har nådd kravet, aspirational som snittet på tvers av
aspirational-KR. De to typene måles mot hver sin målestokk, og et aggregat på
tvers av dem er tvetydig (`okr-framework.md`, committed/aspirational-skillet).
3. **Vurder confidence**:
- Basert på trend og gjenstående tid
@ -90,14 +93,29 @@ Score = (Nåværende - Baseline) / (Target - Baseline)
### Objective: [tekst]
| KR | Baseline | Target | Nå | Score | Trend | Status |
|----|----------|--------|-----|-------|-------|--------|
| KR1: [kort] | X | Y | Z | 0.XX | ↗️/→/↘️ | ✅/⚠️/❌ |
| KR2: [kort] | X | Y | Z | 0.XX | ↗️/→/↘️ | ✅/⚠️/❌ |
| KR3: [kort] | X | Y | Z | 0.XX | ↗️/→/↘️ | ✅/⚠️/❌ |
#### Committed Key Results
**Samlet score:** 0.XX
**Confidence:** [On Track 🟢 | At Risk 🟡 | Off Track 🔴]
| KR | Baseline | Target | Nå | Score | Trend | Avvik | Confidence |
|----|----------|--------|-----|-------|-------|-------|------------|
| KR1: [kort] | X | Y | Z | 0.XX | ↗️/→/↘️ | Ja/Nei | [nivå] |
| KR2: [kort] | X | Y | Z | 0.XX | ↗️/→/↘️ | Ja/Nei | [nivå] |
**Committed: N av M KR har nådd kravet.** Kravet er nådd eller ikke — hvert avvik
forklares for seg, og de summeres ikke til ett tall.
**Confidence, committed:** [On Track 🟢 | At Risk 🟡 | Off Track 🔴]
#### Aspirational Key Results
| KR | Baseline | Target | Nå | Score | Trend | Avvik | Confidence |
|----|----------|--------|-----|-------|-------|-------|------------|
| KR3: [kort] | X | Y | Z | 0.XX | ↗️/→/↘️ | - | [nivå] |
**Snitt aspirational: 0.XX** over N KR. Rundt 0.7 er forventet måloppnåelse —
en lav score her er ikke et avvik.
**Confidence, aspirational:** [On Track 🟢 | At Risk 🟡 | Off Track 🔴]
Nivået i `[nivå]`-cellene settes fra den kanoniske confidence-tabellen i
`okr-framework.md` — ikke fra score.
---

View file

@ -47,7 +47,18 @@ Score = (Nåværende - Baseline) / (Target - Baseline)
- Baseline og target (hvis ikke kjent)
- Dato for måling
2. **Beregn score** per KR og samlet (vektet gjennomsnitt)
Er `/okr:rapport tertial` kjørt for syklusen, finnes tallene allerede i
`rapport-tertial.md` — les den i stedet for å spørre om dem på nytt.
Confidence-kolonnen der står tom med vilje: generatoren eier aritmetikken,
denne kommandoen eier vurderingen. Det er den kolonnen du fyller i steg 3.
2. **Beregn score** per KR, og oppsummer **per type** — aldri som ett felles tall.
Committed og aspirational måles mot hver sin målestokk, og et aggregat på tvers
av dem er tvetydig (`okr-framework.md`, committed/aspirational-skillet):
- **Committed:** hvor mange KR som har nådd kravet. Et committed KR er nådd
eller ikke; et snitt av binære krav er ikke en størrelse.
- **Aspirational:** snittet på tvers av aspirational-KR. Rundt 0.7 er forventet
måloppnåelse, ikke svikt.
3. **Vurder confidence** — sett nivået fra den **kanoniske confidence-tabellen i
`okr-framework.md`** (On Track 🟢 / At Risk 🟡 / Off Track 🔴, sannsynlighet for å
@ -83,17 +94,27 @@ timestamp: "[ISO-8601]"
### Objective: Forbedre trafikksikkerhet i skolesoner
| KR | Baseline | Target | Nå | Score | Status |
|----|----------|--------|-----|-------|--------|
| KR1: Redusere ulykker | 40 | 30 | 35 | 0.50 | At Risk 🟡 |
| KR2: Fartshumper installert | 0% | 100% | 60% | 0.60 | On Track 🟢 |
| KR3: Foreldre-tilfredshet | 60% | 90% | 75% | 0.50 | At Risk 🟡 |
#### Committed Key Results
**Samlet score: 0.53** (vektet gjennomsnitt)
| KR | Baseline | Target | Nå | Score | Avvik | Confidence |
|----|----------|--------|-----|-------|-------|------------|
| KR1: Redusere ulykker | 40 | 30 | 35 | 0.50 | Ja | At Risk 🟡 |
| KR2: Fartshumper installert | 0 | 100 | 60 | 0.60 | Ja | On Track 🟢 |
**Samlet confidence: At Risk 🟡**
- KR1 og KR3 trenger fokus
- KR2 ligger foran plan
**Committed: 0 av 2 KR har nådd kravet.** Et committed KR er nådd eller ikke;
avvikene over skal forklares, ikke rundes av til et snitt.
#### Aspirational Key Results
| KR | Baseline | Target | Nå | Score | Avvik | Confidence |
|----|----------|--------|-----|-------|-------|------------|
| KR3: Foreldre-tilfredshet | 60 | 90 | 75 | 0.50 | - | At Risk 🟡 |
**Snitt aspirational: 0.50** over 1 KR. Rundt 0.7 er forventet måloppnåelse for
aspirational — en lav score her er ikke et avvik og skal ikke rapporteres som ett.
**Confidence, committed:** At Risk 🟡 — KR1 trenger fokus, KR2 ligger foran plan.
**Confidence, aspirational:** At Risk 🟡 — KR3 flater ut.
**Anbefalte tiltak:**
1. Prioriter tiltak for KR1 (sikkerhet er kritisk)

View file

@ -163,6 +163,46 @@ test('(a2) F-c: ingen parallelle confidence-etikettsett utenfor kanon', () => {
);
});
// --- (k) Separasjonsregelen i malene (D6 steg 14) ---
//
// okr-framework.md:557: committed og aspirational boer ikke blandes til ett
// aggregat -- de to typene rapporteres hver for seg. Generatoren
// (lib/syklus-rapport.mjs) haandhever det; malene gjorde det ikke. En regel med to
// lesninger er nettopp defektklassen S38-S40 kostet tre oekter.
//
// Skanne-settet er commands/ + agents/ -- MALENE pluginen emitterer. references/
// staar utenfor med vilje: der foeres en annen diskusjon (per-Objective-aggregering
// i kalkulatoren), og aa dra den inn her ville blandet to spoersmaal i en vakt.
//
// To former, fordi bruddet har to skrivemaater:
// ETIKETT -- "Samlet score: <verdi>" i en malblokk. De andre aksene gaar klar:
// rubrikkens 0-10-skala har ingen verdi paa linjen, og det arkiverte
// datafeltet `samlet_score` er snake_case, ikke "samlet score".
// INSTRUKS -- "samlet (vektet gjennomsnitt)", som ber leseren lage aggregatet.
// En linje som navngir typen er per definisjon differensiert og gaar klar.
const AGGREGAT_ETIKETT = /samlet\s+score[:*\s]*[[\]0-9X_]/i;
const AGGREGAT_INSTRUKS = /\bsamlet\b[^\n]{0,25}vektet\s+gjennomsnitt/i;
test('(k) separasjonsregelen: ingen mal emitterer et udifferensiert samlet-aggregat', () => {
const maler = [...mdFiles('commands'), ...mdFiles('agents')];
assert.ok(maler.length >= 10, `parser-sanity: forventet >= 10 maler, fant ${maler.length}`);
const violations = [];
for (const f of maler) {
readDoc(f).split('\n').forEach((line, i) => {
if (/committed|aspirational/i.test(line)) return;
if (AGGREGAT_ETIKETT.test(line) || AGGREGAT_INSTRUKS.test(line)) {
violations.push(`${f}:${i + 1}: ${line.trim()}`);
}
});
}
assert.deepEqual(
violations,
[],
`udifferensiert aggregat i mal (okr-framework.md:557 -- rapporter typene hver for seg):\n${violations.join('\n')}`,
);
});
// --- F-d kadens x publikum (D1 / review.md 607313e3) ---
// Den forrige vakten bandt kadens-adjektivet DIREKTE til check-in (\s+), og kunne derfor
// ikke feile paa den KANONISKE tabellen: etter "Maanedlig" kommer "**" og en cellevegg,