Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
24996d66bd |
|||
|
9d6c53f6e1 |
|||
|
13f6c28dc0 |
13 changed files with 152 additions and 36 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "dynamisk-rettsstat",
|
"name": "dynamisk-rettsstat",
|
||||||
"displayName": "Den dynamiske rettsstaten",
|
"displayName": "Den dynamiske rettsstaten",
|
||||||
"version": "0.1.0",
|
"version": "0.1.2",
|
||||||
"description": "Plugin for Claude som kjører modellen i Den dynamiske rettsstaten på egne tall: finn leddet som binder, følg tiltaket over tid, simuler egne scenarioer og endre modellen.",
|
"description": "Plugin for Claude som kjører modellen i Den dynamiske rettsstaten på egne tall: finn leddet som binder, følg tiltaket over tid, simuler egne scenarioer og endre modellen.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Kjell Tore Guttormsen"
|
"name": "Kjell Tore Guttormsen"
|
||||||
|
|
|
||||||
3
BIDRA.md
3
BIDRA.md
|
|
@ -4,6 +4,9 @@ Modellen er en første versjon, og notatet *Den dynamiske rettsstaten* er skreve
|
||||||
Har du forbedret modellen, rettet en feil eller prøvd den mot data, tas det gjerne imot. Denne siden sier hvordan du
|
Har du forbedret modellen, rettet en feil eller prøvd den mot data, tas det gjerne imot. Denne siden sier hvordan du
|
||||||
sender det, og hva et bidrag må ha for at det kan vurderes.
|
sender det, og hva et bidrag må ha for at det kan vurderes.
|
||||||
|
|
||||||
|
Arbeidet er avsluttet (november 2026), og det er ikke planlagt nye versjoner. Et bidrag blir derfor ikke nødvendigvis
|
||||||
|
tatt inn her. Lisensen (MIT) lar deg gi ut din egen utgave.
|
||||||
|
|
||||||
## Slik sender du det
|
## Slik sender du det
|
||||||
|
|
||||||
Repositoryet ligger på en egen Forgejo-server der utenforstående ikke kan registrere seg, så bidrag kommer på
|
Repositoryet ligger på en egen Forgejo-server der utenforstående ikke kan registrere seg, så bidrag kommer på
|
||||||
|
|
|
||||||
29
CHANGELOG.md
29
CHANGELOG.md
|
|
@ -2,6 +2,35 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## 2026-11-11 — arbeidet er avsluttet (ingen ny versjon)
|
||||||
|
|
||||||
|
- README og `BIDRA.md` sier nå at arbeidet er avsluttet, og at det ikke er planlagt nye versjoner. Versjon 0.1.2 er den
|
||||||
|
siste. Pluginen selv er ikke endret: ferdighetene, modellen, kjernen og fasiten er de samme som i 0.1.2.
|
||||||
|
|
||||||
|
## 0.1.2 — 2026-11-11
|
||||||
|
|
||||||
|
- Notatet omtaler nå selv at utgangspunktet i modellene med kø i domstolen ikke er en eksakt likevekt (avsnitt 10,
|
||||||
|
«Utgangspunktet i modellene med kø»). README og `docs/forbehold.md` sa at notatet ikke nevner det; det er rettet.
|
||||||
|
Modellen, kjernen og fasiten er uendret: notatets kode er den samme som ved commit 2badc25.
|
||||||
|
|
||||||
|
## 0.1.1 — 2026-11-11
|
||||||
|
|
||||||
|
Etter forfatterens prøve av 0.1.0 i Cowork.
|
||||||
|
|
||||||
|
- README: hva som er målt i Cowork, og hva som ikke er det. Zip-fila fra Forgejo lastes opp som den er, de fire
|
||||||
|
ferdighetene virker, diagnosen og forløpet gir notatets tall, og kontrollen gir «bit for bit som notatet» også med
|
||||||
|
Python 3.13.18, numpy 2.5.3 og scipy 1.18.1 på Linux. Ikke målt der: en egen simulering med figur, installasjon av
|
||||||
|
numpy og scipy, og om en arbeidskopi blir liggende til neste økt.
|
||||||
|
- Rettet: `miljo` sa at kontrollen «sammenligner med toleranse, ikke bit for bit» når numpy eller scipy ikke er
|
||||||
|
notatets versjoner. Det stemte ikke: kontrollen sammenligner alltid byte for byte først, og i Cowork ga numpy 2.5.3
|
||||||
|
bit for bit. Meldingen sier nå at tallene kan avvike i siste siffer, og at kontrollen sier hva de gjør.
|
||||||
|
- Nytt: `kontroll --alt` viser alle linjene som er ulike. Før ble alt etter de 40 første per sammenligning bare
|
||||||
|
talt («… linjer til»), uten noen måte å få dem fram på. Linja sier nå hvordan.
|
||||||
|
- Ferdigheten `simuler`: spørsmålet før kjøringen skal kunne besvares med ja eller nei. I prøven ble det et valg
|
||||||
|
mellom varianter, og kjøringen ble stående.
|
||||||
|
- Ferdigheten `forbedre`: ligger arbeidskopien et sted brukeren ikke åpner selv, som i Cowork, sier Claude hvor, og
|
||||||
|
tilbyr den som zip-fil sammen med kontrollutskriften.
|
||||||
|
|
||||||
## 0.1.0 — 2026-11-11
|
## 0.1.0 — 2026-11-11
|
||||||
|
|
||||||
Første versjon.
|
Første versjon.
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,10 @@ justice chain (mostly non-programmers) and researchers. The note and its code li
|
||||||
- Skill frontmatter has only `name` and `description` (other keys make claude.ai reject an uploaded skill).
|
- Skill frontmatter has only `name` and `description` (other keys make claude.ai reject an uploaded skill).
|
||||||
- `${CLAUDE_PLUGIN_ROOT}` and `${CLAUDE_PLUGIN_DATA}` are substituted in skill text, but they are not environment
|
- `${CLAUDE_PLUGIN_ROOT}` and `${CLAUDE_PLUGIN_DATA}` are substituted in skill text, but they are not environment
|
||||||
variables in Bash. Skills write them literally into the command; `kjor.py` treats an empty `--data` or one containing
|
variables in Bash. Skills write them literally into the command; `kjor.py` treats an empty `--data` or one containing
|
||||||
`${` as not given and falls back to `~/.dynamisk-rettsstat`.
|
`${` as not given and falls back to `~/.dynamisk-rettsstat`. Both were substituted in Cowork too (operator's test
|
||||||
|
2026-11-11: the plugin under `/root/.claude/plugins/synced/<id>/dynamisk-rettsstat`, data under
|
||||||
|
`/root/.claude/plugins/data/dynamisk-rettsstat-synced`). Cowork ran the commands in a Linux machine where numpy and
|
||||||
|
scipy were already installed in the system Python, so the venv path is untested there.
|
||||||
- Skills never invent numbers, show the numbers as understood before computing, divide yearly figures by 12 and say
|
- Skills never invent numbers, show the numbers as understood before computing, divide yearly figures by 12 and say
|
||||||
so, relay script numbers verbatim, carry the caveats, and never install anything without asking. A
|
so, relay script numbers verbatim, carry the caveats, and never install anything without asking. A
|
||||||
`rettsstat-modell/` in the user's folder is used only after asking, and only after `kontroll --rask` on it has been
|
`rettsstat-modell/` in the user's folder is used only after asking, and only after `kontroll --rask` on it has been
|
||||||
|
|
@ -64,7 +67,8 @@ justice chain (mostly non-programmers) and researchers. The note and its code li
|
||||||
- Reproduction check against the note: `.venv/bin/python modell/kjor.py kontroll` (full run; about 1.5 minutes on the
|
- Reproduction check against the note: `.venv/bin/python modell/kjor.py kontroll` (full run; about 1.5 minutes on the
|
||||||
development machine, measured 2026-11-11) or `.venv/bin/python modell/kjor.py kontroll --rask` (skips the full run of
|
development machine, measured 2026-11-11) or `.venv/bin/python modell/kjor.py kontroll --rask` (skips the full run of
|
||||||
`sim.py`). Six parts: core and `fasit/` against the note's checksums, `diagnose`, `forlop`, full run, extensions'
|
`sim.py`). Six parts: core and `fasit/` against the note's checksums, `diagnose`, `forlop`, full run, extensions'
|
||||||
limit cases, scenario runner against `fasit/data`.
|
limit cases, scenario runner against `fasit/data`. `--alt` shows every differing line instead of the first 40 per
|
||||||
|
comparison.
|
||||||
- Try the skills' commands: `python3 modell/kjor.py diagnose eksempler/eksempel_domstol.json`,
|
- Try the skills' commands: `python3 modell/kjor.py diagnose eksempler/eksempel_domstol.json`,
|
||||||
`python3 modell/kjor.py forlop eksempler/eksempel_domstol.json`,
|
`python3 modell/kjor.py forlop eksempler/eksempel_domstol.json`,
|
||||||
`python3 modell/kjor.py scenario eksempler/scenarioer/sjokkstorrelse_kjede.json --ut <scratch folder>` (`forlop` and
|
`python3 modell/kjor.py scenario eksempler/scenarioer/sjokkstorrelse_kjede.json --ut <scratch folder>` (`forlop` and
|
||||||
|
|
|
||||||
60
README.md
60
README.md
|
|
@ -9,6 +9,10 @@ arbeider i straffesakskjeden og for forskere som vil prøve, etterprøve eller f
|
||||||
Prinsippet bak notatet: «Innsatsen for å håndheve lover og regler bør løpende stå i forhold til hvor mye, og hvor
|
Prinsippet bak notatet: «Innsatsen for å håndheve lover og regler bør løpende stå i forhold til hvor mye, og hvor
|
||||||
alvorlig, de faktisk brytes.» Straffebud og strafferammer ligger fast.
|
alvorlig, de faktisk brytes.» Straffebud og strafferammer ligger fast.
|
||||||
|
|
||||||
|
**Status:** Arbeidet er avsluttet (november 2026), og det er ikke planlagt nye versjoner. Versjon 0.1.2 er den siste.
|
||||||
|
Pluginen kan brukes og bygges videre på fritt etter lisensen. Innspill og rettelser kan fortsatt sendes på e-post, se
|
||||||
|
[Slik er arbeidet gjort](#slik-er-arbeidet-gjort).
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
I Claude Code:
|
I Claude Code:
|
||||||
|
|
@ -18,16 +22,18 @@ claude plugin marketplace add https://git.fromaitochitta.com/open/ktg-plugin-mar
|
||||||
claude plugin install dynamisk-rettsstat@ktg-plugin-marketplace
|
claude plugin install dynamisk-rettsstat@ktg-plugin-marketplace
|
||||||
```
|
```
|
||||||
|
|
||||||
I Claude Cowork: last ned repositoryet som zip fra Forgejo-siden (`https://git.fromaitochitta.com/open/dynamisk-rettsstat`)
|
I Claude Cowork: last ned zip-fila for nyeste utgivelse fra
|
||||||
og last det opp som plugin.
|
[utgivelsessiden](https://git.fromaitochitta.com/open/dynamisk-rettsstat/releases) og last den opp som plugin. Cowork
|
||||||
|
tar zip-fila slik den er.
|
||||||
|
|
||||||
Det som trengs:
|
Det som trengs:
|
||||||
- **Python 3.** Flaskehalsdiagnosen trenger ikke noe mer.
|
- **Python 3.** Flaskehalsdiagnosen trenger ikke noe mer.
|
||||||
- **numpy og scipy** for forløpet over tid, simuleringene og kontrollen. Mangler de, spør Claude før noe installeres,
|
- **numpy og scipy** for forløpet over tid, simuleringene og kontrollen. Mangler de, spør Claude før noe installeres,
|
||||||
og installerer dem da fra PyPI i en egen mappe for pluginen (krever internett). Ingenting installeres uten at du
|
og installerer dem da fra PyPI i en egen mappe for pluginen (krever internett). Ingenting installeres uten at du
|
||||||
sier ja.
|
sier ja. I Cowork fantes begge fra før da pluginen ble prøvd, så ingenting ble installert.
|
||||||
|
|
||||||
Status: prøvd i Claude Code. Ikke prøvd i Cowork ennå.
|
Status: prøvd i Claude Code og i Cowork. Hva som er målt i Cowork, og hva som ikke er det, står under «Prøvd i
|
||||||
|
Cowork» lenger ned.
|
||||||
|
|
||||||
## Hva du kan gjøre med den
|
## Hva du kan gjøre med den
|
||||||
|
|
||||||
|
|
@ -125,9 +131,10 @@ Notatet, simuleringskoden og PDF-ene ligger i
|
||||||
låst med sha256 i `modell/kjerne/KILDE.json`. En test feiler hvis en av dem endres.
|
låst med sha256 i `modell/kjerne/KILDE.json`. En test feiler hvis en av dem endres.
|
||||||
- Kontrollen måler kjernen og fasiten mot notatets egne sjekksummer, kjører hele notatets simulering og
|
- Kontrollen måler kjernen og fasiten mot notatets egne sjekksummer, kjører hele notatets simulering og
|
||||||
sammenligner med notatets 22 datafiler og utskriftene, og kjører notatets scenariofiler gjennom scenariokjøreren.
|
sammenligner med notatets 22 datafiler og utskriftene, og kjører notatets scenariofiler gjennom scenariokjøreren.
|
||||||
Målt 2026-11-11 med Python 3.14.0, numpy 2.5.4 og scipy 1.18.1: alle 22 datafilene er like byte for byte, og 14 av
|
Målt 2026-11-11 med Python 3.14.0, numpy 2.5.4 og scipy 1.18.1 (macOS): alle 22 datafilene er like byte for byte,
|
||||||
14 scenariofiler gjenskaper notatets datafiler byte for byte. Med andre versjoner av numpy og scipy sier kontrollen
|
og 14 av 14 scenariofiler gjenskaper notatets datafiler byte for byte. Samme dag i Cowork med Python 3.13.18,
|
||||||
om tallene er like innenfor én enhet i siste siffer.
|
numpy 2.5.3 og scipy 1.18.1 (Linux): samme resultat. Med andre versjoner av numpy og scipy sier kontrollen om
|
||||||
|
tallene er like bit for bit eller innenfor én enhet i siste siffer.
|
||||||
- Scenariokjøreren kaller kjernen uendret. Scenariofilene i `eksempler/scenarioer/notatet/` gjenskaper notatets
|
- Scenariokjøreren kaller kjernen uendret. Scenariofilene i `eksempler/scenarioer/notatet/` gjenskaper notatets
|
||||||
datafiler, og testene sammenligner dem med fasiten.
|
datafiler, og testene sammenligner dem med fasiten.
|
||||||
|
|
||||||
|
|
@ -142,8 +149,10 @@ python3 -m venv .venv
|
||||||
.venv/bin/python -m pytest
|
.venv/bin/python -m pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
Kontrollen skal ende med `Nivå: bit for bit som notatet.` når Python, numpy og scipy er versjonene over.
|
Kontrollen skal ende med `Nivå: bit for bit som notatet.` når Python, numpy og scipy er versjonene over. Med andre
|
||||||
`pip install --group dev` trenger pip 25.1 eller nyere.
|
versjoner kan den ende med `Nivå: innenfor toleranse`; det er ikke sett i noen av målingene. `kontroll --alt` viser
|
||||||
|
alle linjene som er ulike, ikke bare de 40 første per sammenligning. `pip install --group dev` trenger pip 25.1
|
||||||
|
eller nyere.
|
||||||
|
|
||||||
## Forbedre modellen selv
|
## Forbedre modellen selv
|
||||||
|
|
||||||
|
|
@ -164,6 +173,31 @@ skal kunne endre den:
|
||||||
Forskere som bruker git, kan også klone dette repositoryet og starte Claude Code med `claude --plugin-dir .` i mappa.
|
Forskere som bruker git, kan også klone dette repositoryet og starte Claude Code med `claude --plugin-dir .` i mappa.
|
||||||
Slik sender du en forbedring tilbake: [BIDRA.md](BIDRA.md).
|
Slik sender du en forbedring tilbake: [BIDRA.md](BIDRA.md).
|
||||||
|
|
||||||
|
## Prøvd i Cowork
|
||||||
|
|
||||||
|
Forfatteren prøvde v0.1.0 i Cowork i Claude-skrivebordsappen 2026-11-11. Dette ble målt:
|
||||||
|
|
||||||
|
- **Installasjon.** Zip-fila for v0.1.0 fra Forgejo ble lastet opp uten advarsler, og de fire ferdighetene var på
|
||||||
|
plass.
|
||||||
|
- **Diagnosen** ga tallene som står i dette dokumentet, på eksempeltallene (1,28 og 19 %), på de norske tallene
|
||||||
|
(1,09 / 1,04 / 0,88 / 1,09) og på egne tall oppgitt per år. Claude delte årstallene på 12, viste tallene slik de
|
||||||
|
var forstått, og spurte før regningen.
|
||||||
|
- **Forløpet** ga 7,2 måneder, 19 % nå og 12 % om 12 måneder, også i en ny økt.
|
||||||
|
- **Kontrollen** endte med `Nivå: bit for bit som notatet.`: 22 av 22 datafiler og 14 av 14 scenariofiler.
|
||||||
|
- **Miljøet.** Cowork kjørte kommandoene i en Linux-maskin (Ubuntu 24.04) der Python 3.13.18, numpy 2.5.3 og scipy
|
||||||
|
1.18.1 fantes fra før. Pluginen installerte derfor ingenting.
|
||||||
|
- **Arbeidskopi.** En kopi med frafallet fra domstolskøen satt til 0,02 ga `Nivå: endret`, med 11 av 22 datafiler
|
||||||
|
flyttet. Kopien ble laget i Linux-maskinen, og Claude ga den tilbake som en zip-fil sammen med kontrollutskriften.
|
||||||
|
|
||||||
|
Ikke målt i Cowork:
|
||||||
|
|
||||||
|
- En egen simulering fra «hva om …» til tabell og figur. Prøven stoppet ved spørsmålet Claude stilte før kjøringen.
|
||||||
|
Scenariokjøreren selv ble kjørt av kontrollen.
|
||||||
|
- Installasjon av numpy og scipy fra pluginen, siden de fantes fra før.
|
||||||
|
- Om en arbeidskopi blir liggende til neste økt.
|
||||||
|
|
||||||
|
Windows er ikke prøvd, verken i Cowork eller i Claude Code.
|
||||||
|
|
||||||
## Status og begrensninger
|
## Status og begrensninger
|
||||||
|
|
||||||
- Modellen er ikke kalibrert på norske data. Parameterne er stiliserte, og simuleringene illustrerer mekanismer. De
|
- Modellen er ikke kalibrert på norske data. Parameterne er stiliserte, og simuleringene illustrerer mekanismer. De
|
||||||
|
|
@ -172,10 +206,12 @@ Slik sender du en forbedring tilbake: [BIDRA.md](BIDRA.md).
|
||||||
- Bare ett ledd har kø i modellen. Alle simuleringene antar feilfrie observasjoner, og resultatene er enkeltbaner
|
- Bare ett ledd har kø i modellen. Alle simuleringene antar feilfrie observasjoner, og resultatene er enkeltbaner
|
||||||
uten parameterusikkerhet.
|
uten parameterusikkerhet.
|
||||||
- I modellene med kø i domstolen er utgangspunktet nesten, men ikke helt, en likevekt: uten noe sjokk går
|
- I modellene med kø i domstolen er utgangspunktet nesten, men ikke helt, en likevekt: uten noe sjokk går
|
||||||
kriminaliteten fra 1,000 til 1,018 og saksbehandlingstiden fra 3,0 til 4,6 måneder over 240 måneder. Notatet nevner
|
kriminaliteten fra 1,000 til 1,018 og saksbehandlingstiden fra 3,0 til 4,6 måneder over 240 måneder. Notatet
|
||||||
det ikke. En liten del av det kjedescenarioene viser, er denne driften, og sammendraget viser hvor langt den har kommet fram
|
omtaler det under begrensningene i avsnitt 10. En liten del av det kjedescenarioene viser, er denne driften, og
|
||||||
til sjokket.
|
sammendraget viser hvor langt den har kommet fram til sjokket.
|
||||||
- Kostnader og gevinster er ikke regnet i kroner.
|
- Kostnader og gevinster er ikke regnet i kroner.
|
||||||
|
- Svarene er tekst og tabeller, med tilbud om en figur etter en simulering. Pluginen bruker ikke det Cowork ellers
|
||||||
|
kan av visuelle svar. Det er en opplagt videreutvikling for den som vil bygge videre på den.
|
||||||
- Diagnosen regner på tallene slik de er oppgitt, og kapasitetsbehovet er et grovt anslag.
|
- Diagnosen regner på tallene slik de er oppgitt, og kapasitetsbehovet er et grovt anslag.
|
||||||
|
|
||||||
Alle forbeholdene, for modellen, diagnosen, forløpet og de norske tallene: [docs/forbehold.md](docs/forbehold.md).
|
Alle forbeholdene, for modellen, diagnosen, forløpet og de norske tallene: [docs/forbehold.md](docs/forbehold.md).
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,14 @@ Ferdighetene tar med de forbeholdene som gjelder for svaret de gir.
|
||||||
måleimperfeksjon. Resultatene er enkeltbaner uten parameterusikkerhet.
|
måleimperfeksjon. Resultatene er enkeltbaner uten parameterusikkerhet.
|
||||||
- **Bare ett ledd har kø.** I notatets simuleringer er det domstolen; i `forlop` er det leddet som binder i dine tall.
|
- **Bare ett ledd har kø.** I notatets simuleringer er det domstolen; i `forlop` er det leddet som binder i dine tall.
|
||||||
Etterforskning, påtale og straffegjennomføring har ellers verken kø, frafall eller kapasitet i modellen.
|
Etterforskning, påtale og straffegjennomføring har ellers verken kø, frafall eller kapasitet i modellen.
|
||||||
- **Utgangspunktet i modellene med kø er nesten, men ikke helt, en likevekt.** Notatet kaller starttilstanden
|
- **Utgangspunktet i modellene med kø er nesten, men ikke helt, en likevekt.** I modellene der domstolen har kø,
|
||||||
«utgangslikevekten», men i modellene der domstolen har kø, står den ikke helt i ro: saker som faller fra køen
|
står starttilstanden ikke helt i ro: saker som faller fra køen
|
||||||
(henleggelse, foreldelse), blir aldri trukket fra kriminaliteten i modellens regnskap. Kjørt helt uten sjokk, med
|
(henleggelse, foreldelse), blir aldri trukket fra kriminaliteten i modellens regnskap. Kjørt helt uten sjokk, med
|
||||||
notatets verdier, går kriminaliteten fra 1,000 til 1,007 i måned 11, 1,015 i måned 120 og 1,018 i måned 240, og
|
notatets verdier, går kriminaliteten fra 1,000 til 1,007 i måned 11, 1,015 i måned 120 og 1,018 i måned 240, og
|
||||||
saksbehandlingstiden fra 3,0 til 3,1, 4,2 og 4,6 måneder, fortsatt stigende (målt 2026-11-11 med notatets kode,
|
saksbehandlingstiden fra 3,0 til 3,1, 4,2 og 4,6 måneder, fortsatt stigende (målt 2026-11-11 med notatets kode,
|
||||||
`eksempler/scenarioer/uten_sjokk_kjede.json`). Notatet nevner det ikke. En liten del av det kjedescenarioene viser
|
`eksempler/scenarioer/uten_sjokk_kjede.json`). Notatet omtaler det under begrensningene i avsnitt 10. En liten del
|
||||||
etter sjokket, er denne driften.
|
av det kjedescenarioene viser etter sjokket, er denne driften, og den er ikke trukket fra i notatets tabeller og
|
||||||
|
figurer.
|
||||||
- **Kostnader er ikke regnet i kroner.** Målfunksjonen er stilt opp, men ikke brukt. Ingen kostnader eller gevinster
|
- **Kostnader er ikke regnet i kroner.** Målfunksjonen er stilt opp, men ikke brukt. Ingen kostnader eller gevinster
|
||||||
er tallfestet, og modellens størrelser er normaliserte, ikke årsverk eller kroner.
|
er tallfestet, og modellens størrelser er normaliserte, ikke årsverk eller kroner.
|
||||||
- **Beslutningsreglene er stiliserte.** Reglene for påtale og budsjett er representasjoner av hvordan myndighetene kan
|
- **Beslutningsreglene er stiliserte.** Reglene for påtale og budsjett er representasjoner av hvordan myndighetene kan
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ Kommandoer:
|
||||||
forlop <fil> ["ledd"] stabilitetssjekk og forløp måned for måned (numpy og scipy)
|
forlop <fil> ["ledd"] stabilitetssjekk og forløp måned for måned (numpy og scipy)
|
||||||
scenario <fil> [--ut <mappe>] kjør en scenariofil (numpy og scipy)
|
scenario <fil> [--ut <mappe>] kjør en scenariofil (numpy og scipy)
|
||||||
notatet [--ut <mappe>] kjør notatets simuleringer uendret, om lag 1-2 min (numpy og scipy)
|
notatet [--ut <mappe>] kjør notatets simuleringer uendret, om lag 1-2 min (numpy og scipy)
|
||||||
kontroll [--rask] kontroller at modellen regner som notatet
|
kontroll [--rask] [--alt] kontroller at modellen regner som notatet (--alt: vis alle ulike linjer)
|
||||||
miljo [--opprett] vis Python, numpy og scipy; --opprett installerer dem i en egen mappe
|
miljo [--opprett] vis Python, numpy og scipy; --opprett installerer dem i en egen mappe
|
||||||
arbeidskopi <mappe> lag en kopi av modellen som du kan endre
|
arbeidskopi <mappe> lag en kopi av modellen som du kan endre
|
||||||
|
|
||||||
|
|
@ -568,8 +568,8 @@ def rapport_miljo(valg: Valg) -> None:
|
||||||
if samme_som_notatet(regner, laast):
|
if samme_som_notatet(regner, laast):
|
||||||
print("Versjonene av numpy og scipy er de samme som notatets, så kontroll kan gi bit for bit.")
|
print("Versjonene av numpy og scipy er de samme som notatets, så kontroll kan gi bit for bit.")
|
||||||
else:
|
else:
|
||||||
print("Versjonene av numpy og scipy er ikke de samme som notatets: kontroll sammenligner da "
|
print("Versjonene av numpy og scipy er ikke de samme som notatets. Tallene kan da avvike i siste "
|
||||||
"med toleranse, ikke bit for bit.")
|
"siffer; kontroll sier om de er like bit for bit eller innenfor toleranse.")
|
||||||
|
|
||||||
|
|
||||||
def kjor_prosess(kommando: list[str]) -> int:
|
def kjor_prosess(kommando: list[str]) -> int:
|
||||||
|
|
@ -608,8 +608,8 @@ def opprett_miljo(valg: Valg) -> int:
|
||||||
print()
|
print()
|
||||||
rapport_miljo(valg)
|
rapport_miljo(valg)
|
||||||
if toleranse:
|
if toleranse:
|
||||||
print("\nNumpy og scipy er ikke notatets låste versjoner. Resultatene kontrolleres da med toleranse, "
|
print("\nNotatets låste versjoner av numpy og scipy lot seg ikke installere, så nyere versjoner er "
|
||||||
"ikke bit for bit.")
|
"installert. Kjør kontroll for å se om tallene er like bit for bit eller innenfor toleranse.")
|
||||||
return OK
|
return OK
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@
|
||||||
"""Gjenskapingskontroll: sjekk at modellen i denne mappa regner som notatet.
|
"""Gjenskapingskontroll: sjekk at modellen i denne mappa regner som notatet.
|
||||||
|
|
||||||
Bruk:
|
Bruk:
|
||||||
python3 kjor.py kontroll [--rask]
|
python3 kjor.py kontroll [--rask] [--alt]
|
||||||
python3 kontroll.py [--rask] (med en Python som har numpy og scipy)
|
python3 kontroll.py [--rask] [--alt] (med en Python som har numpy og scipy)
|
||||||
|
|
||||||
|
--alt viser alle linjene som er ulike. Uten den vises de 40 første per sammenligning, og
|
||||||
|
resten telles.
|
||||||
|
|
||||||
Kontrollene, hver med én linje dom og detaljer bare ved avvik:
|
Kontrollene, hver med én linje dom og detaljer bare ved avvik:
|
||||||
1. Kjernen og fasit: sha256 for filene i kjerne/ og fasit/ mot notatets verdier, som står som
|
1. Kjernen og fasit: sha256 for filene i kjerne/ og fasit/ mot notatets verdier, som står som
|
||||||
|
|
@ -118,7 +121,8 @@ SCENARIO_TREGE = ("mpc11",)
|
||||||
|
|
||||||
LIK, TOLERANSE, ENDRET, IKKE_KJORT = "lik", "toleranse", "endret", "ikke kjørt"
|
LIK, TOLERANSE, ENDRET, IKKE_KJORT = "lik", "toleranse", "endret", "ikke kjørt"
|
||||||
RANG = {LIK: 0, TOLERANSE: 1, IKKE_KJORT: 2, ENDRET: 3}
|
RANG = {LIK: 0, TOLERANSE: 1, IKKE_KJORT: 2, ENDRET: 3}
|
||||||
MAKS_LINJER = 40 # linjer med forskjeller som vises per sammenligning
|
MAKS_LINJER = 40 # linjer med forskjeller som vises per sammenligning (alle med --alt)
|
||||||
|
VISNING = {"alt": False} # settes av --alt i main()
|
||||||
SLINGRING = 1e-9 # relativ slingring når avviket sammenlignes med én enhet i siste siffer
|
SLINGRING = 1e-9 # relativ slingring når avviket sammenlignes med én enhet i siste siffer
|
||||||
UTVIDELSER = "Utvidelser" # merkelappen for kontroll 5
|
UTVIDELSER = "Utvidelser" # merkelappen for kontroll 5
|
||||||
|
|
||||||
|
|
@ -220,8 +224,9 @@ def vis_tall(x: float) -> str:
|
||||||
def forskjeller(fasit: list[str], naa: list[str]) -> list[str]:
|
def forskjeller(fasit: list[str], naa: list[str]) -> list[str]:
|
||||||
"""Linjene som er ulike, som en kort diff (notatet / nå)."""
|
"""Linjene som er ulike, som en kort diff (notatet / nå)."""
|
||||||
linjer = list(difflib.unified_diff(fasit, naa, "notatet", "nå", lineterm="", n=0))
|
linjer = list(difflib.unified_diff(fasit, naa, "notatet", "nå", lineterm="", n=0))
|
||||||
if len(linjer) > MAKS_LINJER:
|
if len(linjer) > MAKS_LINJER and not VISNING["alt"]:
|
||||||
linjer = [*linjer[:MAKS_LINJER], f"... ({len(linjer) - MAKS_LINJER} linjer til)"]
|
linjer = [*linjer[:MAKS_LINJER],
|
||||||
|
f"... ({len(linjer) - MAKS_LINJER} linjer til; «kontroll --alt» viser alle)"]
|
||||||
return linjer
|
return linjer
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -594,10 +599,11 @@ def niva(dommer: list[Dom], *, rask: bool, arbeidskopi: bool) -> list[str]:
|
||||||
|
|
||||||
def main(argv: list[str]) -> int:
|
def main(argv: list[str]) -> int:
|
||||||
"""Kjør kontrollene og skriv dommen. Returnerer exit-koden."""
|
"""Kjør kontrollene og skriv dommen. Returnerer exit-koden."""
|
||||||
if argv not in ([], ["--rask"]):
|
if len(set(argv)) != len(argv) or not set(argv) <= {"--rask", "--alt"}:
|
||||||
print("Bruk: kjor.py kontroll [--rask]", file=sys.stderr)
|
print("Bruk: kjor.py kontroll [--rask] [--alt]", file=sys.stderr)
|
||||||
return 2
|
return 2
|
||||||
rask = argv == ["--rask"]
|
rask = "--rask" in argv
|
||||||
|
VISNING["alt"] = "--alt" in argv
|
||||||
arbeidskopi = (ROT / ARBEIDSKOPI_MERKE).is_file()
|
arbeidskopi = (ROT / ARBEIDSKOPI_MERKE).is_file()
|
||||||
regnemiljo = har_numpy_scipy()
|
regnemiljo = har_numpy_scipy()
|
||||||
print(f"Kontroll av modellen i {MODELL}" + (" (arbeidskopi)" if arbeidskopi else "") + "\n", flush=True)
|
print(f"Kontroll av modellen i {MODELL}" + (" (arbeidskopi)" if arbeidskopi else "") + "\n", flush=True)
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" ar
|
||||||
`rettsstat-modell/`, og sier hvilket nivå kontrollen gir den.
|
`rettsstat-modell/`, og sier hvilket nivå kontrollen gir den.
|
||||||
- `modell/kontroll.py` i kopien har notatets sjekksummer som faste verdier; det er dem kontrollen måler mot. Endre
|
- `modell/kontroll.py` i kopien har notatets sjekksummer som faste verdier; det er dem kontrollen måler mot. Endre
|
||||||
den ikke: da sier kontrollen ikke lenger noe om notatet.
|
den ikke: da sier kontrollen ikke lenger noe om notatet.
|
||||||
|
- Ligger kopien et sted brukeren ikke åpner selv (i Cowork kjører kommandoene i øktas egen Linux-maskin, og kopien
|
||||||
|
havner der), si hvor den ligger, og tilby å gi den som en zip-fil sammen med hele utskriften fra kontrollen.
|
||||||
|
|
||||||
**Forskere som bruker git** kan i stedet klone pluginens repository (`https://git.fromaitochitta.com/open/dynamisk-rettsstat.git`),
|
**Forskere som bruker git** kan i stedet klone pluginens repository (`https://git.fromaitochitta.com/open/dynamisk-rettsstat.git`),
|
||||||
endre der og starte Claude Code med pluginen fra klonen: `claude --plugin-dir .` i mappa. Da bruker ferdighetene
|
endre der og starte Claude Code med pluginen fra klonen: `claude --plugin-dir .` i mappa. Da bruker ferdighetene
|
||||||
|
|
@ -131,6 +133,8 @@ python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" --
|
||||||
|
|
||||||
- Den fulle kontrollen kjører hele notatets simulering og tar et par minutter. Mens du prøver deg fram, kan du legge
|
- Den fulle kontrollen kjører hele notatets simulering og tar et par minutter. Mens du prøver deg fram, kan du legge
|
||||||
til `--rask` (hopper over den fulle kjøringen av `sim.py`); kjør den fulle før du sier hva endringen gjør.
|
til `--rask` (hopper over den fulle kjøringen av `sim.py`); kjør den fulle før du sier hva endringen gjør.
|
||||||
|
- Utskriften viser de 40 første linjene som er ulike i hver sammenligning, og teller resten («… linjer til»). Vil
|
||||||
|
brukeren se alt som har flyttet seg, eller skal utskriften sendes med en forbedring, legg til `--alt`.
|
||||||
- Kontrollen måler mot notatets egne sjekksummer, som står fast i `modell/kontroll.py`, ikke mot filene i kopien.
|
- Kontrollen måler mot notatets egne sjekksummer, som står fast i `modell/kontroll.py`, ikke mot filene i kopien.
|
||||||
Den har seks deler, nummerert slik i utskriften:
|
Den har seks deler, nummerert slik i utskriften:
|
||||||
1. kjernen (`sim.py`, `diagnose.py`, `forlop.py`) og fasiten (27 filer) mot notatets sjekksummer;
|
1. kjernen (`sim.py`, `diagnose.py`, `forlop.py`) og fasiten (27 filer) mot notatets sjekksummer;
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ Exit-koder:
|
||||||
python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" miljo --opprett
|
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
|
Gjengi det kommandoen sier (blant annet om versjonene av numpy og scipy er notatets), og kjør
|
||||||
forløpet på nytt. Feiler installasjonen, gjengi meldingen og si at diagnosen fortsatt kan brukes uten tilleggene.
|
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:
|
- **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,
|
- *Feil i inndata*, *Fant ikke fila*, *ikke gyldig JSON* eller *Fant ikke leddet*: gjengi meldingen med vanlige ord,
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,9 @@ stopper kjøringen uansett valg når politiets effektivitet, tilliten, innsatsen
|
||||||
Si det rett ut: i den modellen er det en endring i kjernen, og det er ferdigheten `forbedre`. Den koblede modellen
|
Si det rett ut: i den modellen er det en endring i kjernen, og det er ferdigheten `forbedre`. Den koblede modellen
|
||||||
uten beslutningsregler (`simulate_chain`) kan ofte svare på det samme spørsmålet; tilby den.
|
uten beslutningsregler (`simulate_chain`) kan ofte svare på det samme spørsmålet; tilby den.
|
||||||
|
|
||||||
Spør: «Skal jeg kjøre dette?» Kjør ikke før brukeren har sagt ja.
|
Spør: «Skal jeg kjøre dette?» Kjør ikke før brukeren har sagt ja. Spørsmålet står alene til slutt og skal kunne
|
||||||
|
besvares med ja eller nei. Legg ikke et valg mellom varianter inn i det («de tre, eller alle fire?»): da er «ja» ikke
|
||||||
|
lenger et svar, og kjøringen blir stående. Forslag til flere kjøringer kommer etter svaret, i trinn 7.
|
||||||
|
|
||||||
## 3. Skriv scenariofila
|
## 3. Skriv scenariofila
|
||||||
|
|
||||||
|
|
@ -136,7 +138,7 @@ Exit-koder:
|
||||||
python3 "${CLAUDE_PLUGIN_ROOT}/modell/kjor.py" --data "${CLAUDE_PLUGIN_DATA}" miljo --opprett
|
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 på
|
Gjengi det kommandoen sier (blant annet om versjonene av numpy og scipy er notatets), og kjør på
|
||||||
nytt. Feiler installasjonen, gjengi meldingen og si at diagnosen fortsatt kan brukes uten tilleggene.
|
nytt. Feiler installasjonen, gjengi meldingen og si at diagnosen fortsatt kan brukes uten tilleggene.
|
||||||
- **2**: skriptet har stoppet med en melding, og ingenting er skrevet. Les den:
|
- **2**: skriptet har stoppet med en melding, og ingenting er skrevet. Les den:
|
||||||
- *Feil i scenariofila … startlikevekt: startpunktet er ikke en likevekt …*: en grunnparameter er endret. Gjengi
|
- *Feil i scenariofila … startlikevekt: startpunktet er ikke en likevekt …*: en grunnparameter er endret. Gjengi
|
||||||
|
|
|
||||||
|
|
@ -345,7 +345,12 @@ def test_opprett_faller_tilbake_og_sier_toleranse(
|
||||||
monkeypatch.setattr(kjor_modul, "rapport_miljo", lambda _valg: None)
|
monkeypatch.setattr(kjor_modul, "rapport_miljo", lambda _valg: None)
|
||||||
assert kjor_modul.main(["--data", str(tmp_path), "miljo", "--opprett"]) == 0
|
assert kjor_modul.main(["--data", str(tmp_path), "miljo", "--opprett"]) == 0
|
||||||
assert [k[-2:] for k in kommandoer] == [["-r", str(MODELL / "requirements.txt")], ["numpy>=2.0", "scipy"]]
|
assert [k[-2:] for k in kommandoer] == [["-r", str(MODELL / "requirements.txt")], ["numpy>=2.0", "scipy"]]
|
||||||
assert "kontrolleres da med toleranse, ikke bit for bit" in capsys.readouterr().out
|
ut = capsys.readouterr().out
|
||||||
|
assert "lot seg ikke installere, så nyere versjoner er installert" in ut
|
||||||
|
assert "bit for bit eller innenfor toleranse" in ut
|
||||||
|
# Measured in Cowork 2026-11-11: numpy 2.5.3 (not the pinned 2.5.4) still gave bit for bit,
|
||||||
|
# so the message must not promise a tolerance comparison.
|
||||||
|
assert "ikke bit for bit" not in ut
|
||||||
|
|
||||||
|
|
||||||
def test_opprett_som_feiler_gir_kode_3(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
def test_opprett_som_feiler_gir_kode_3(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,20 @@ def test_tekst_endret(fasit: str, naa: str) -> None:
|
||||||
assert resultat.detaljer
|
assert resultat.detaljer
|
||||||
|
|
||||||
|
|
||||||
|
def test_mange_forskjeller_kuttes_og_alt_viser_resten(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
"""Cowork-prøven 2026-11-11: 274 linjer ble kuttet uten at brukeren kunne få dem fram."""
|
||||||
|
fasit = [f"linje {i}" for i in range(60)]
|
||||||
|
naa = [f"rad {i}" for i in range(60)]
|
||||||
|
kort = kontroll.forskjeller(fasit, naa)
|
||||||
|
assert len(kort) == kontroll.MAKS_LINJER + 1
|
||||||
|
assert kort[-1].endswith("linjer til; «kontroll --alt» viser alle)")
|
||||||
|
monkeypatch.setattr(kontroll, "VISNING", {"alt": True})
|
||||||
|
alle = kontroll.forskjeller(fasit, naa)
|
||||||
|
assert "-linje 59" in alle
|
||||||
|
assert "+rad 59" in alle
|
||||||
|
assert not any("linjer til" in linje for linje in alle)
|
||||||
|
|
||||||
|
|
||||||
DAT = "t K Q\n0.00000 1.00000 0.29100\n0.50000 1.10000 0.30000\n"
|
DAT = "t K Q\n0.00000 1.00000 0.29100\n0.50000 1.10000 0.30000\n"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -183,6 +197,18 @@ def test_manglende_fasit(lett_kopi: Path, hjem: Path) -> None:
|
||||||
assert "norge_2025: fant ikke fasit/diagnose_norge_2025.txt" in prosess.stdout
|
assert "norge_2025: fant ikke fasit/diagnose_norge_2025.txt" in prosess.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_kontroll_avviser_ukjent_valg(hjem: Path) -> None:
|
||||||
|
prosess = kjor("kontroll", "--alle", hjem=hjem)
|
||||||
|
assert prosess.returncode == 2
|
||||||
|
assert "Bruk: kjor.py kontroll [--rask] [--alt]" in prosess.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def test_kontroll_med_alt_gir_samme_dom(lett_kopi: Path, hjem: Path) -> None:
|
||||||
|
prosess = kjor("--modell", str(lett_kopi), "kontroll", "--rask", "--alt", hjem=hjem)
|
||||||
|
assert prosess.returncode == 0, prosess.stdout + prosess.stderr
|
||||||
|
assert "Nivå (uten full kjøring, --rask): bit for bit som notatet." in prosess.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_diagnose_krever_eksakt_likhet(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
def test_diagnose_krever_eksakt_likhet(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
"""Funn 10: én enhet i siste siffer i diagnosen er endret, ikke innenfor toleranse."""
|
"""Funn 10: én enhet i siste siffer i diagnosen er endret, ikke innenfor toleranse."""
|
||||||
fasit = tmp_path / "fasit"
|
fasit = tmp_path / "fasit"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue