feat(okr): sandbagging-vakt i alle tre rapportformene
This commit is contained in:
parent
052e4d4e86
commit
47e7ac9e2a
3 changed files with 180 additions and 31 deletions
|
|
@ -97,6 +97,62 @@ function aspirationalSnitt(okrer) {
|
|||
return `**Snitt aspirational: ${snitt.toFixed(2)}** over ${scorer.length} KR${hale}.`;
|
||||
}
|
||||
|
||||
// --- Sandbagging-vakten (steg 13): felles for alle tre rapportformene ---
|
||||
//
|
||||
// Regelen: en aspirational-OKR med lav score presenteres ALDRI som avvik
|
||||
// (okr-offentlig-governance.md:148-156). Den er kodet ETT sted og brukes av alle
|
||||
// formene, fordi en regel som maa gjentas per form er en regel som glipper i den
|
||||
// fjerde.
|
||||
//
|
||||
// Begrunnelsen er kausal, ikke normativ (okr-framework.md:158-161, Bogsnes):
|
||||
// faar aspirational-scoren konsekvenser i rapporteringen, er target og forecast
|
||||
// re-bundlet -- og da kommer sandbaggingen tilbake av strukturell noedvendighet,
|
||||
// uansett hvor disiplinert den som setter maalet er. Vakten beskytter altsaa
|
||||
// ikke aspirational-KR-et; den beskytter maalsettingen i neste syklus.
|
||||
|
||||
// Avvik er committed-only. Predikatet er det samme som Avvik-kolonnen bruker --
|
||||
// via beregnScore, aldri naa >= target -- saa listen og kolonnen ikke kan gi
|
||||
// ulikt svar om samme KR.
|
||||
function avvikListe(okrer) {
|
||||
const rader = [];
|
||||
for (const okr of okrer) {
|
||||
for (const kr of okr.krer) {
|
||||
if (kr.type !== 'committed' || formatAvvik(kr, true) !== 'Ja') continue;
|
||||
rader.push(
|
||||
`- ${okr.tittel}: ${kr.navn} -- naa ${kr.naa} mot krav ${kr.target} `
|
||||
+ `(score ${formatScore(beregnScore(kr))})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return rader;
|
||||
}
|
||||
|
||||
// Overskriften varierer med mottakeren; filteret gjoer det ikke.
|
||||
function avvikSeksjon(okrer, overskrift) {
|
||||
const rader = avvikListe(okrer);
|
||||
return [
|
||||
`## ${overskrift}`,
|
||||
'',
|
||||
'Kun committed KR staar her: et committed krav er naadd eller ikke. Aspirational',
|
||||
'KR er holdt utenfor med vilje -- se forventningen til aspirational under.',
|
||||
'',
|
||||
...(rader.length > 0 ? rader : ['Ingen committed KR ligger under kravet i denne syklusen.']),
|
||||
'',
|
||||
];
|
||||
}
|
||||
|
||||
// Forventningsteksten hoerer i rapporten, ikke bare i koden: mottakeren i
|
||||
// departementet leser ikke 0.7 som suksess med mindre det staar eksplisitt
|
||||
// (governance-regel 1).
|
||||
const ASPIRATIONAL_RAMME = [
|
||||
'Aspirational KR forventes aa lande rundt 0.7 med hoey varians, og vurderes',
|
||||
'paa snittet paa tvers av alle aspirational-OKR -- ikke paa ett enkelt KR.',
|
||||
'En lav score er derfor maaloppnaaelse, ikke svikt, og et aspirational KR staar',
|
||||
'aldri i avviks-seksjonen. Fikk lav aspirational-score konsekvenser i',
|
||||
'rapporteringen, ville maal og prognose vaert bundlet sammen igjen -- og',
|
||||
'sandbagging fulgt strukturelt, ikke som et disiplinproblem.',
|
||||
];
|
||||
|
||||
// Felles inngangsvakt for alle rapportformene. En form som stille rapporterte
|
||||
// en tom syklus ville produsert et styringsdokument uten innhold, som ser
|
||||
// komplett ut.
|
||||
|
|
@ -167,13 +223,14 @@ export function tertialrapport(syklus, opts = {}) {
|
|||
);
|
||||
}
|
||||
|
||||
ut.push(...avvikSeksjon(syklus.okrer, 'Avvik som skal forklares'));
|
||||
|
||||
if (aspirational.antallKr > 0) {
|
||||
ut.push(
|
||||
'## Aspirational Key Results',
|
||||
'',
|
||||
// Governance-invariant 1: typen merkes, slik at 0.7 ikke leses som svikt.
|
||||
'Aspirational KR forventes aa lande rundt 0.7 med hoey varians, og vurderes',
|
||||
'paa snittet paa tvers av alle aspirational-OKR -- ikke paa ett enkelt KR.',
|
||||
...ASPIRATIONAL_RAMME,
|
||||
'',
|
||||
...aspirational.linjer,
|
||||
);
|
||||
|
|
@ -276,6 +333,8 @@ export function arsrapportDelIII(syklus, opts = {}) {
|
|||
ut.push('### Vurdering av maaloppnaaelse', '', ...VURDERINGSFELT, '');
|
||||
}
|
||||
|
||||
ut.push(...avvikSeksjon(syklus.okrer, 'Avvik som skal forklares'));
|
||||
|
||||
// Snittet hoerer PAA TVERS av Objectives (okr-framework.md:557) og staar derfor
|
||||
// ikke i noen enkelt Objective-seksjon. Committed har bevisst ingen motpart:
|
||||
// et snitt av binaere krav er ikke en stoerrelse.
|
||||
|
|
@ -284,8 +343,7 @@ export function arsrapportDelIII(syklus, opts = {}) {
|
|||
ut.push(
|
||||
'## Aspirational maaloppnaaelse paa tvers av Objectives',
|
||||
'',
|
||||
'Aspirational KR forventes aa lande rundt 0.7 med hoey varians, og vurderes',
|
||||
'paa snittet -- ikke paa ett enkelt KR.',
|
||||
...ASPIRATIONAL_RAMME,
|
||||
'',
|
||||
snitt,
|
||||
'',
|
||||
|
|
@ -309,23 +367,6 @@ export function arsrapportDelIII(syklus, opts = {}) {
|
|||
// og form fastsettes i departementets hovedinstruks. Et underlag som foregrep
|
||||
// kadensen ville gjeninnfoert den samme uverifiserte paastanden i maskinform.
|
||||
|
||||
// Avvik er committed-only. Predikatet er det samme som Avvik-kolonnen bruker --
|
||||
// via beregnScore, aldri naa >= target -- saa listen og kolonnen ikke kan gi
|
||||
// ulikt svar om samme KR.
|
||||
function avvikListe(okrer) {
|
||||
const rader = [];
|
||||
for (const okr of okrer) {
|
||||
for (const kr of okr.krer) {
|
||||
if (kr.type !== 'committed' || formatAvvik(kr, true) !== 'Ja') continue;
|
||||
rader.push(
|
||||
`- ${okr.tittel}: ${kr.navn} -- naa ${kr.naa} mot krav ${kr.target} `
|
||||
+ `(score ${formatScore(beregnScore(kr))})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return rader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bygger underlaget til et etatsstyringsmoete for en syklus lest av lesSyklus().
|
||||
*
|
||||
|
|
@ -366,15 +407,11 @@ export function etatsstyringsunderlag(syklus, opts = {}) {
|
|||
}
|
||||
}
|
||||
|
||||
const avvik = avvikListe(syklus.okrer);
|
||||
ut.push(
|
||||
'## Avvik som krever departementets oppmerksomhet',
|
||||
'',
|
||||
...(avvik.length > 0
|
||||
? avvik
|
||||
: ['Ingen committed KR ligger under kravet i denne syklusen.']),
|
||||
'',
|
||||
);
|
||||
ut.push(...avvikSeksjon(syklus.okrer, 'Avvik som krever departementets oppmerksomhet'));
|
||||
|
||||
// Forventningen staar rett under avvikslisten, der spoersmaalet «hvorfor er
|
||||
// ikke DETTE et avvik?» faktisk oppstaar hos mottakeren.
|
||||
ut.push('## Aspirational Key Results - forventning', '', ...ASPIRATIONAL_RAMME, '');
|
||||
|
||||
// Hjemmelen for at tildelingsbrevet SKAL inneholde styringsparametere er
|
||||
// bestemmelser om oekonomistyring i staten («bestemmelsene») punkt 1.5,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue