Compare commits
No commits in common. "main" and "v0.1.0" have entirely different histories.
13 changed files with 36 additions and 152 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "dynamisk-rettsstat",
|
"name": "dynamisk-rettsstat",
|
||||||
"displayName": "Den dynamiske rettsstaten",
|
"displayName": "Den dynamiske rettsstaten",
|
||||||
"version": "0.1.2",
|
"version": "0.1.0",
|
||||||
"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,9 +4,6 @@ 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,35 +2,6 @@
|
||||||
|
|
||||||
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,10 +43,7 @@ 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`. Both were substituted in Cowork too (operator's test
|
`${` as not given and falls back to `~/.dynamisk-rettsstat`.
|
||||||
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
|
||||||
|
|
@ -67,8 +64,7 @@ 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`. `--alt` shows every differing line instead of the first 40 per
|
limit cases, scenario runner against `fasit/data`.
|
||||||
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,10 +9,6 @@ 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:
|
||||||
|
|
@ -22,18 +18,16 @@ 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 zip-fila for nyeste utgivelse fra
|
I Claude Cowork: last ned repositoryet som zip fra Forgejo-siden (`https://git.fromaitochitta.com/open/dynamisk-rettsstat`)
|
||||||
[utgivelsessiden](https://git.fromaitochitta.com/open/dynamisk-rettsstat/releases) og last den opp som plugin. Cowork
|
og last det opp som plugin.
|
||||||
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. I Cowork fantes begge fra før da pluginen ble prøvd, så ingenting ble installert.
|
sier ja.
|
||||||
|
|
||||||
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
|
Status: prøvd i Claude Code. Ikke prøvd i Cowork ennå.
|
||||||
Cowork» lenger ned.
|
|
||||||
|
|
||||||
## Hva du kan gjøre med den
|
## Hva du kan gjøre med den
|
||||||
|
|
||||||
|
|
@ -131,10 +125,9 @@ 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 (macOS): alle 22 datafilene er like byte for byte,
|
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
|
||||||
og 14 av 14 scenariofiler gjenskaper notatets datafiler byte for byte. Samme dag i Cowork med Python 3.13.18,
|
14 scenariofiler gjenskaper notatets datafiler byte for byte. Med andre versjoner av numpy og scipy sier kontrollen
|
||||||
numpy 2.5.3 og scipy 1.18.1 (Linux): samme resultat. Med andre versjoner av numpy og scipy sier kontrollen om
|
om tallene er like innenfor én enhet i siste siffer.
|
||||||
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.
|
||||||
|
|
||||||
|
|
@ -149,10 +142,8 @@ 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. Med andre
|
Kontrollen skal ende med `Nivå: bit for bit som notatet.` når Python, numpy og scipy er versjonene over.
|
||||||
versjoner kan den ende med `Nivå: innenfor toleranse`; det er ikke sett i noen av målingene. `kontroll --alt` viser
|
`pip install --group dev` trenger pip 25.1 eller nyere.
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -173,31 +164,6 @@ 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
|
||||||
|
|
@ -206,12 +172,10 @@ Windows er ikke prøvd, verken i Cowork eller i Claude Code.
|
||||||
- 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
|
kriminaliteten fra 1,000 til 1,018 og saksbehandlingstiden fra 3,0 til 4,6 måneder over 240 måneder. Notatet nevner
|
||||||
omtaler det under begrensningene i avsnitt 10. En liten del av det kjedescenarioene viser, er denne driften, og
|
det ikke. En liten del av det kjedescenarioene viser, er denne driften, og sammendraget viser hvor langt den har kommet fram
|
||||||
sammendraget viser hvor langt den har kommet fram til sjokket.
|
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,14 +19,13 @@ 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.** I modellene der domstolen har kø,
|
- **Utgangspunktet i modellene med kø er nesten, men ikke helt, en likevekt.** Notatet kaller starttilstanden
|
||||||
står starttilstanden ikke helt i ro: saker som faller fra køen
|
«utgangslikevekten», men i modellene der domstolen har kø, står den 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 omtaler det under begrensningene i avsnitt 10. En liten del
|
`eksempler/scenarioer/uten_sjokk_kjede.json`). Notatet nevner det ikke. En liten del av det kjedescenarioene viser
|
||||||
av det kjedescenarioene viser etter sjokket, er denne driften, og den er ikke trukket fra i notatets tabeller og
|
etter sjokket, er denne driften.
|
||||||
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] [--alt] kontroller at modellen regner som notatet (--alt: vis alle ulike linjer)
|
kontroll [--rask] kontroller at modellen regner som notatet
|
||||||
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. Tallene kan da avvike i siste "
|
print("Versjonene av numpy og scipy er ikke de samme som notatets: kontroll sammenligner da "
|
||||||
"siffer; kontroll sier om de er like bit for bit eller innenfor toleranse.")
|
"med toleranse, ikke bit for bit.")
|
||||||
|
|
||||||
|
|
||||||
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("\nNotatets låste versjoner av numpy og scipy lot seg ikke installere, så nyere versjoner er "
|
print("\nNumpy og scipy er ikke notatets låste versjoner. Resultatene kontrolleres da med toleranse, "
|
||||||
"installert. Kjør kontroll for å se om tallene er like bit for bit eller innenfor toleranse.")
|
"ikke bit for bit.")
|
||||||
return OK
|
return OK
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,8 @@
|
||||||
"""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] [--alt]
|
python3 kjor.py kontroll [--rask]
|
||||||
python3 kontroll.py [--rask] [--alt] (med en Python som har numpy og scipy)
|
python3 kontroll.py [--rask] (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
|
||||||
|
|
@ -121,8 +118,7 @@ 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 (alle med --alt)
|
MAKS_LINJER = 40 # linjer med forskjeller som vises per sammenligning
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -224,9 +220,8 @@ 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 and not VISNING["alt"]:
|
if len(linjer) > MAKS_LINJER:
|
||||||
linjer = [*linjer[:MAKS_LINJER],
|
linjer = [*linjer[:MAKS_LINJER], f"... ({len(linjer) - MAKS_LINJER} linjer til)"]
|
||||||
f"... ({len(linjer) - MAKS_LINJER} linjer til; «kontroll --alt» viser alle)"]
|
|
||||||
return linjer
|
return linjer
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -599,11 +594,10 @@ 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 len(set(argv)) != len(argv) or not set(argv) <= {"--rask", "--alt"}:
|
if argv not in ([], ["--rask"]):
|
||||||
print("Bruk: kjor.py kontroll [--rask] [--alt]", file=sys.stderr)
|
print("Bruk: kjor.py kontroll [--rask]", file=sys.stderr)
|
||||||
return 2
|
return 2
|
||||||
rask = "--rask" in argv
|
rask = argv == ["--rask"]
|
||||||
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,8 +62,6 @@ 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
|
||||||
|
|
@ -133,8 +131,6 @@ 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 versjonene av numpy og scipy er notatets), og kjør
|
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.
|
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,9 +91,7 @@ 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ørsmålet står alene til slutt og skal kunne
|
Spør: «Skal jeg kjøre dette?» Kjør ikke før brukeren har sagt ja.
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -138,7 +136,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 versjonene av numpy og scipy er notatets), og kjør på
|
Gjengi det kommandoen sier (blant annet om resultatene da kontrolleres bit for bit eller med toleranse), 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,12 +345,7 @@ 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"]]
|
||||||
ut = capsys.readouterr().out
|
assert "kontrolleres da med toleranse, ikke bit for bit" in 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,20 +45,6 @@ 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"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -197,18 +183,6 @@ 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