feat: model core, launcher, reproduction check and the first two skills

The core in modell/kjerne/ is an unmodified copy of sim.py, diagnose.py and
forlop.py from den-dynamiske-rettsstaten @2badc25, pinned by sha256.
kjor.py is the single entry point; kontroll.py reproduces the note's 22 data
files and printed results. Skills: diagnose and forlop (Norwegian).

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-11-11 13:53:32 +01:00
commit 464ad38b49
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
51 changed files with 11207 additions and 0 deletions

138
skills/diagnose/SKILL.md Normal file
View file

@ -0,0 +1,138 @@
---
name: diagnose
description: "Finner leddet som binder i straffesakskjeden fra egne tall, med modellen i notatet Den dynamiske rettsstaten: utnyttelse og restanse per ledd, tiltakstype etter Theory of Constraints (utnytt, led saker utenom, utvid) og hvor mye kapasitet som trengs. Bruk når noen vil finne flaskehalsen, se om politi, påtale, domstol eller kriminalomsorg binder, regne ut kapasitetsbehov eller prøve verktøyet på eksempeltall eller offentlige norske tall. Utløses av «finn flaskehalsen», «hvilket ledd binder», «hvor er flaskehalsen i straffesakskjeden», «kjør diagnosen», «se på restansene våre», «hvor mye kapasitet trenger domstolen», «prøv flaskehalsdiagnosen», «find the bottleneck in the criminal justice chain», «run the bottleneck diagnosis»."
---
# Finn leddet som binder
Ferdigheten går fra tall per ledd i straffesakskjeden til leddet som binder, hvilken type tiltak det krever, og hvor
mye kapasitet som trengs. Den kjører diagnosen i notatet *Den dynamiske rettsstaten* (trinn (c)–(e) i metoden,
avsnitt 7.7 og 9.5) og trenger bare Python 3.
Brukeren arbeider ofte i straffesakskjeden og er ikke programmerer. Snakk vanlig norsk. Nevn ikke filnavn,
kommandoer, feltnavn eller JSON med mindre brukeren spør etter dem.
## Regler
- **Finn aldri på et tall.** Mangler et tall, spør. Vet ikke brukeren, si hva verktøyet gjør uten det (se
standardverdiene i `${CLAUDE_PLUGIN_ROOT}/docs/inndata.md`), og la brukeren velge.
- **Vis tallene slik du har forstått dem, og få et ja før du regner.**
- **Årstall deles på 12, og du sier det.** Det gjelder strømmer (saker inn, kapasitet). Restanser er antall saker og
deles ikke.
- **Gjengi skriptets tall ordrett**, i skriptets rekkefølge. Regn aldri om, avrund aldri annerledes og «forbedre»
aldri et tall. Vil brukeren vite hva som skjer med andre tall, endrer du fila og kjører på nytt.
- **Ta med forbeholdene** som gjelder (under, og `${CLAUDE_PLUGIN_ROOT}/docs/forbehold.md`).
- **Installer aldri noe uten å spørre.** Diagnosen trenger ingen tillegg.
## 1. Skaff tallene
For hvert ledd trengs:
| Spør om | Enhet |
|---|---|
| navnet på leddet | |
| saker inn per måned nå | saker/mnd |
| saker leddet kan avgjøre per måned, slik det virker nå | saker/mnd |
| restansen nå | saker |
| målet: saksbehandlingstid i måneder, *eller* en akseptabel restanse i saker | mnd eller saker |
Og, hvis brukeren har dem (spør etter at de påkrevde er på plass):
- prognose for saker inn når balansen er gjenopprettet (uten prognose brukes strømmen nå);
- hvor stor andel av sakene som kan ledes til forenklede reaksjoner (for eksempel 20 %);
- restansen for tolv måneder siden (gir observert vekst i restansen);
- saker som avsluttes uten behandling og som er regnet med i kapasiteten, for eksempel henlagt på grunn av manglende
kapasitet.
Ledd oppgis i kjedens rekkefølge (politi før påtale før domstol før kriminalomsorg).
**Brukeren har tallene klare.** Ta imot en limt tabell, et regneark, en CSV-fil eller en JSON-fil. Les den, finn hvilke
kolonner som svarer til hva, og spør om det som er uklart. Er det uklart om et tall gjelder per år eller per måned,
spør.
**Brukeren har ikke tallene klare.** Gå gjennom ett ledd om gangen og still ett spørsmål om gangen. Si hvorfor tallet
trengs når det ikke er opplagt.
**Brukeren har ingen tall ennå.** Tilby å kjøre et av eksemplene, og si hva det er:
- *Stilisert eksempel* (`${CLAUDE_PLUGIN_ROOT}/eksempler/eksempel_domstol.json`): modellens egne tall, ikke norske.
Domstolen binder, og svaret gjenskaper avsnitt 9.5 i notatet (utnyttelse 1,28 og 19 % mer kapasitet).
- *Offentlige norske tall for 2025* (`${CLAUDE_PLUGIN_ROOT}/eksempler/norge_2025.json`): politi og påtale, tingrett,
lagmannsrett og fengsel, fra offentlige kilder. Flere av tallene er anslag; kildene står i fila.
Eksemplene kjøres direkte fra pluginen. Vil brukeren endre dem, kopierer du fila til arbeidsmappa først.
Vær særlig oppmerksom på:
- **Kapasitet** er det leddet avgjør per måned nå. Kapasitet som er bevilget, men ikke virker ennå, skal ikke med; si
at den trekkes fra behovet etterpå.
- **Avgjorte saker som kapasitet.** Er kapasiteten hentet fra avgjorte saker, og noen av dem ble avsluttet uten
behandling, spør hvor mange. De oppgis som skjult avgang og trekkes fra av verktøyet, ikke av deg.
- **Mål.** Er restansen bare en del av køen (for eksempel saker eldre enn tre måneder), passer et mål i antall saker
bedre enn en saksbehandlingstid.
## 2. Vis tallene og få et ja
Vis en liten tabell før du regner:
| Ledd | Inn per mnd | Kapasitet per mnd | Restanse | Mål | Annet |
|---|---|---|---|---|---|
Skriv under tabellen hva du har gjort med tallene, for eksempel «Årstallene er delt på 12» eller «Restansen er ikke
delt, den er et antall saker». Spør: «Stemmer dette?» Regn ikke før brukeren har sagt ja.
## 3. Skriv inndatafila
Skriv tallene som en JSON-fil i brukerens arbeidsmappe, for eksempel `rettsstat-tall.json`. Formatet, feltnavnene og
reglene står i `${CLAUDE_PLUGIN_ROOT}/docs/inndata.md`; les den før du skriver fila første gang. Feltnavnene skrives
nøyaktig som der, uten æ, ø og å: koden ser bort fra felt den ikke kjenner, så en skrivefeil gir stille en
standardverdi. Skriv i `merknad` hvor tallene kommer fra og hva som er regnet om. Finnes fila fra før, spør før du
overskriver den.
## 4. Kjør diagnosen
```
python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" diagnose <fil>
```
- På Windows heter tolken `python`.
- `<fil>` er hele stien til inndatafila.
- Har brukerens arbeidsmappe en egen arbeidskopi av modellen (mappa `rettsstat-modell/` med `modell/kjor.py` inni),
legger du til `--modell <hele stien til rettsstat-modell/modell>` før `diagnose`, og sier til brukeren: «Jeg bruker
din egen versjon av modellen i rettsstat-modell.» Bruk ellers pluginens modell.
Exit-koder:
- **0**: diagnosen er regnet. Gå til trinn 5.
- **2**: feil i inndata. Gjengi meldingen fra skriptet med vanlige ord (den sier hvilket ledd og hvilket tall), rett
tallet sammen med brukeren, vis den rettede tabellen og kjør på nytt. Slutter meldingen med «Uventet feil i …», er
det en feil i koden, ikke i tallene: gjengi den og si at diagnosen ikke ble regnet.
- **Annen kode, eller `python3` finnes ikke**: gjengi meldingen som den er og si at diagnosen ikke ble regnet. Gjett
ikke på et svar.
## 5. Presenter svaret
1. **Vis utskriften slik skriptet skrev den**, i en kodeblokk, i samme rekkefølge. Ikke avrund, regn om eller
formater tallene på nytt.
2. **Les den med vanlige ord**, kort:
- hvilket ledd som binder, og hva utnyttelsen betyr (over 1: det kommer inn flere saker enn leddet avgjør);
- tiltakene i rekkefølgen skriptet gir: utnytt leddet først (tapt tid, ikke regnet), led saker utenom hvis det er
oppgitt en andel, og utvid bare hvis det ikke rekker;
- kapasitetsbehovet, og hva det bygger på (prognosen eller strømmen nå, restansen over målet avviklet over 24
måneder, 95 % utnyttelse som mål);
- linjene om andre ledd: like ledd som ikke kan skilles, ledd som også er over full utnyttelse (skranken kan flytte
seg dit), og ledd etter skranken, som bare viser det som slipper gjennom.
- Står det «Ingen ledd binder», si det rett ut. Står det at restansen vokser uten at noe ledd er over full
utnyttelse, be brukeren se på tallene for saker inn og kapasitet i de leddene.
3. **Forbehold** som alltid tas med:
- Utnyttelse, restanse og kapasitetsbehov er regnet fra brukerens tall. De faste verdiene i regningen (avvikling over
24 måneder, 95 % utnyttelse som mål) er valg i notatets regel, ikke målt.
- «Saksbeh.tid» er restanse delt på kapasitet, ikke målt saksbehandlingstid.
- Kapasitet som er bevilget, men ikke virker ennå, er ikke regnet med. Trekk den fra behovet.
- Verktøyet erstatter ikke budsjettarbeidet og sier ingenting om enkeltsaker.
Ta i tillegg med det som gjelder for dette svaret: like ledd, skjult avgang, og for de norske tallene forbeholdene i
`${CLAUDE_PLUGIN_ROOT}/docs/forbehold.md` (fengselstallene er anslag og følsomme for hva som regnes med; politiets
og SSBs tall teller ikke det samme).
4. **Tilby neste steg**: «Vil du se hva som skjer måned for måned hvis anbefalingen følges, og om styringen tåler sin
egen forsinkelse?» Det er ferdigheten `forlop`, som bruker samme fil. Si at den trenger to vanlige
regnebiblioteker for Python, og at du spør før noe installeres.
Spør brukeren «hva om …» (for eksempel en annen kapasitet eller en annen andel ledet utenom), lag en kopi av fila med
det ene tallet endret, vis endringen, kjør på nytt og vis de to svarene ved siden av hverandre.

146
skills/forlop/SKILL.md Normal file
View file

@ -0,0 +1,146 @@
---
name: forlop
description: "Følger tiltaket for leddet som binder i straffesakskjeden måned for måned, og sjekker om styringen tåler sin egen forsinkelse, med modellen i notatet Den dynamiske rettsstaten: stabilitetssjekk, budsjettvedtak, kapasitet, restanse og saksbehandlingstid over tid, med og uten tiltak, og hva det betyr for resten av kjeden. Bruk etter flaskehalsdiagnosen, eller når noen spør hva som skjer over tid. Utløses av «følg tiltaket over tid», «vis forløpet», «hva skjer hvis vi følger anbefalingen», «når er restansen borte», «tåler styringen forsinkelsen», «stabilitetssjekk», «kjør forløpet», «show the time course», «is the control loop stable»."
---
# Følg tiltaket over tid
Ferdigheten viser hva som skjer måned for måned når anbefalingen fra diagnosen følges, og om styringen tåler sin egen
forsinkelse. Den bruker simuleringen i notatet *Den dynamiske rettsstaten* (den koordinerte regelen i avsnitt 8.5,
gjennomregnet i avsnitt 9.5) og leser samme fil som diagnosen. Den trenger Python 3 med numpy og scipy.
Brukeren arbeider ofte i straffesakskjeden og er ikke programmerer. Snakk vanlig norsk. Nevn ikke filnavn,
kommandoer, feltnavn eller JSON med mindre brukeren spør etter dem.
## Regler
- **Finn aldri på et tall.** Mangler et tall, spør, eller si hvilken standardverdi verktøyet bruker og la brukeren
velge.
- **Vis tallene slik du har forstått dem, og få et ja før du regner.**
- **Årstall deles på 12, og du sier det.** Restanser er antall saker og deles ikke.
- **Gjengi skriptets tall ordrett**, i skriptets rekkefølge. Regn aldri om, avrund aldri annerledes og «forbedre»
aldri et tall.
- **Si hva som er brukerens tall og hva som er modellens.** Kapasitet, restanse og saksbehandlingstid følger tallene i
fila. Kriminalitet, tillit og politiets innsats følger modellens stiliserte parametere, som ikke er kalibrert på norske
data.
- **Installer aldri noe uten å spørre.**
## 1. Tallene
Forløpet bruker samme fil som diagnosen. Er diagnosen kjørt i samtalen, bruk den fila. Ellers skaffer du tallene per
ledd som ferdigheten `diagnose` beskriver (navn, saker inn og kapasitet per måned, restanse, mål), og kan tilby de to
eksemplene i `${CLAUDE_PLUGIN_ROOT}/eksempler/`: `eksempel_domstol.json` (stiliserte tall, gjenskaper avsnitt 9.5) og
`norge_2025.json` (offentlige norske tall for 2025, flere av dem anslag). Formatet står i
`${CLAUDE_PLUGIN_ROOT}/docs/inndata.md`.
Forløpet kan bruke tre ting til. Spør om dem, men bare når brukeren har tallene:
| Spør om | Uten svar brukes |
|---|---|
| Hvor mange måneder går fra kriminalitetsbildet endrer seg til innsatsen er endret (statistikk, beslutning, iverksetting)? | 3 måneder |
| Hvor kraftig reagerer innsatsen: hvor mange prosent mer innsats per prosent over målet? | 3 (10 % over målet gir 30 % mer innsats) |
| Hvor mange saker kom inn per måned før strømmen begynte å øke? | 95 % av kapasiteten |
De to første er regime A i notatet. Si det når du bruker dem. De legges i `styring` i fila; det tredje er
`innstromning_for_okning` i leddet.
**Hvilket ledd.** Uten valg følger forløpet leddet diagnosen peker på. Vil brukeren se et annet ledd, oppgis navnet
nøyaktig slik det står i fila.
Vis tallene som en liten tabell, med styringen under, si hva som er regnet om, og få et ja før du kjører.
## 2. Kjør forløpet
```
python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" forlop <fil>
python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" forlop <fil> "<navn på ledd>"
```
- På Windows heter tolken `python`.
- `<fil>` er hele stien til inndatafila.
- Har brukerens arbeidsmappe en egen arbeidskopi av modellen (mappa `rettsstat-modell/` med `modell/kjor.py` inni),
legger du til `--modell <hele stien til rettsstat-modell/modell>` før `forlop`, og sier til brukeren: «Jeg bruker din
egen versjon av modellen i rettsstat-modell.»
- En kjøring tar noen sekunder.
Exit-koder:
- **0**: skriptet har svart. Det kan også bety at forløpet ikke ble regnet; se trinn 3.
- **3**: numpy eller scipy mangler. Si i én setning: «Forløpet trenger to vanlige regnebiblioteker for Python, numpy og
scipy. Skal jeg installere dem i en egen mappe for denne pluginen?» Installer bare hvis svaret er ja:
```
python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" miljo --opprett
```
Gjengi det kommandoen sier (blant annet om resultatene da kontrolleres bit for bit eller med toleranse), og kjør
forløpet på nytt. Feiler installasjonen, gjengi meldingen og si at diagnosen fortsatt kan brukes uten tilleggene.
- **2**: skriptet har stoppet med en melding. Les den:
- *Feil i inndata*, *Fant ikke fila*, *ikke gyldig JSON* eller *Fant ikke leddet*: gjengi meldingen med vanlige ord,
rett sammen med brukeren og kjør på nytt.
- Meldingen begynner med *Forløpet …* (for eksempel at leddet ikke var i balanse før økningen, at prognosen ikke er
høyere enn strømmen før økningen, eller at den er for høy): tallene ligger utenfor det modellen dekker. Si det med
vanlige ord. Spør om tallet for saker inn før økningen er kjent (uten det brukes 95 % av kapasiteten), og si at
diagnosen gjelder uansett. Endre aldri et tall bare for at forløpet skal gå.
- *Intern kontroll feilet* eller *Kjenner ikke igjen vedtaket*: modellens kode er endret slik at forløpet ikke lenger
stemmer med simuleringen. Si det, og regn ikke noe selv. Bruker brukeren en egen arbeidskopi, er det der endringen
ligger.
- *Uventet feil i …*: en feil i koden, ikke i tallene. Gjengi meldingen og si at forløpet ikke ble regnet.
- **Annen kode, eller `python3` finnes ikke**: gjengi meldingen og si at forløpet ikke ble regnet.
## 3. Presenter svaret
Vis utskriften slik skriptet skrev den, i en kodeblokk, i samme rekkefølge. Ikke avrund, regn om eller formater tallene
på nytt. Les den så for brukeren, del for del.
**Stabilitetssjekken.** Den kritiske forsinkelsen er den lengste forsinkelsen styringen tåler før den selv skaper
svingninger, der satsinger og kutt avløser hverandre. Er forsinkelsen kortere, er styringen stabil, og marginen står i
utskriften. Er den lengre, sier skriptet hvilke to veier som finnes: dempe reaksjonen eller korte ned forsinkelsen.
Sjekken bruker modellens stiliserte tall for hvor fort innsatsen virker.
**Forløpet.**
- *Slik er tallene lagt inn*: gjengi punktene. De sier hva som er tatt fra fila, hva som er antatt, hvor forløpet
starter, og eventuelle avvik og forbehold. «Nå» er første budsjettvedtak etter økningen; raden «-3» er tidspunktet
tallene i fila gjelder.
- *Vedtak*: budsjettet vedtar én gang i året, og bestilt kapasitet virker gradvis fra 6 til 24 måneder etter vedtak.
Si om første vedtak er det samme som diagnosen regnet ut (skriptet sier det).
- *Tabellen*: kapasitet i saker per måned, andel ledet utenom, restanse i saker, saksbehandlingstid i måneder (restanse
delt på kapasitet, ikke målt). Politiinnsats og kriminalitet er relative: 1 er nivået før økningen. Tillit var 0,80
før økningen.
- *Med og uten tiltak*: hva det koster i kapasitet, og hva det gir i saksbehandlingstid, tillit og kriminalitet.
- *Faller til ro eller ikke*: faller forløpet ikke til ro, er sluttallene ikke en ny balanse.
**Resten av kjeden.** Politiets innsats, saker ledet utenom (hvor de havner, er ikke regnet), hvor mange flere saker
leddet avgjør, og hva det betyr for leddene som står etter i fila: tar de det unna, eller flytter skranken seg dit?
**Når skriptet skriver «Forløp: ikke regnet».** Stabilitetssjekken står fortsatt. Forklar grunnen skriptet gir:
- *Styringen er ustabil*: det finnes ingen ny balanse å dimensjonere etter. Styringen må rettes først, ved svakere
reaksjon eller kortere forsinkelse. Tilby å kjøre på nytt med andre tall for styringen hvis brukeren har dem.
- *Prognosen faller ikke til ro*: styringen er for nær grensen eller for treg, så det finnes ikke ett tall å
dimensjonere etter. Skriptet foreslår kortere forsinkelse.
- *Kriminaliteten eller innsatsen faller for lavt mens restansen avvikles*: restansen er mange ganger større enn
strømmen, og modellen holder ikke da. Diagnosen gjelder alene.
Står det «Forløp: ingen ledd binder», er det ikke noe tiltak å følge over tid.
**Forbehold** som alltid tas med:
- Kapasitet, restanse og saksbehandlingstid følger brukerens tall. Kriminalitet, tillit og politiets innsats følger
modellens stiliserte parametere, ikke kalibrert på norske data. Rekkefølgen og retningen er poenget, ikke tallene.
Forløpet er ikke en prognose.
- Bare leddet som binder, har kø i modellen. Det regnes som leddet som tar imot sakene politiets innsats gir (domstolen
i notatet).
- Verktøyet erstatter ikke budsjettarbeidet og sier ingenting om enkeltsaker.
Ta i tillegg med forbeholdene som gjelder dette svaret, fra `${CLAUDE_PLUGIN_ROOT}/docs/forbehold.md` (avsnittet om
forløpet): for eksempel at en restanse som har vokst lenge, virker i modellen først etter start, at kriminaliteten i
modellen faller under nivået før økningen når en stor restanse avvikles, og at kapasitet bestilt for å avvikle
restansen kan bli stående.
## 4. Neste steg
Tilby det som passer:
- kjøre på nytt med en annen forsinkelse eller reaktivitet («hva om forsinkelsen er 6 måneder?»);
- følge et annet ledd, for eksempel det skranken flytter seg til;
- kjøre diagnosen, hvis den ikke er kjørt.
Ved «hva om …»: lag en kopi av fila med det ene tallet endret, vis endringen, kjør på nytt og vis de to svarene ved
siden av hverandre, med skriptets tall.