The operator tested v0.1.0 in Cowork on 2026-11-11. README now says what was measured there and what was not. - miljo: no longer claims that kontroll compares "with tolerance, not bit for bit" when numpy or scipy differ from the note's versions. kontroll always compares byte for byte first, and numpy 2.5.3 gave bit for bit. - kontroll --alt: show every differing line. The cut-off line now names the option instead of only counting the lines left out. - skill simuler: the question before a run must be answerable with yes or no. In the test it became a choice between variants and the run stalled. - skill forbedre: offer the working copy as a zip when the user cannot open the folder it was made in, as in Cowork. 263 tests pass; full kontroll: bit for bit with the note. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
7 KiB
7 KiB
dynamisk-rettsstat
This file is for development sessions in this repo. It is not loaded as plugin context, and claude plugin validate
warns about a CLAUDE.md in the plugin root; that warning is expected.
Context
A Claude plugin (Claude Code and Cowork) that runs the model behind the concept note Den dynamiske rettsstaten on the
user's own numbers: find the binding link in the criminal justice chain (diagnose), follow the measure over time
(forlop), run scenarios (simuler) and change the model (forbedre). Users are Norwegian: people working in the
justice chain (mostly non-programmers) and researchers. The note and its code live in
~/repos/den-dynamiske-rettsstaten (read-only from here). Open, non-commercial; nothing here is for sale.
Stack
- Skills only:
skills/<name>/SKILL.md. No hooks, no MCP servers, no mod, no top-levelbin/(Cowork refuses a plugin with one). modell/kjor.py: the single entry point, Python 3.9+ standard library only. Finds a Python with numpy and scipy for the commands that need them; installs nothing unlessmiljo --opprettis run.modell/kjerne/:sim.py,diagnose.py,forlop.py, unmodified copies from the note's repo, pinned by sha256 inmodell/kjerne/KILDE.json. numpy and scipy pinned inmodell/requirements.txt(as the note).fasit/: reference output (22 data files and 5 printouts, 27 files) thatkontrollcompares against.modell/scenario.py(scenario runner over the core's five simulators),modell/kontroll.py(reproduction check),modell/arbeidskopi.py(copies the model to a folder the user owns),modell/utvidelser/(mechanisms outside the core; each must reproduce the core exactly in a limit case).docs/:inndata.md,scenarioformat.md,modellkart.md,utvidelser.md,forbehold.md, Norwegian. The test for extensions reads the template inutvidelser.mdbetween the markers<!-- mal:start -->and<!-- mal:slutt -->.eksempler/:eksempel_domstol.json(stylized),norge_2025.json(public Norwegian figures),scenarioer/(six scenarios of our own, andnotatet/with 21 files that regenerate 20 of the note's 22 data files).
Conventions
- Never edit
modell/kjerne/. It is synced from the note's repo, and these change together in one commit: the three files copied at the new commit; the commit and sha256 values inmodell/kjerne/KILDE.json;fasit/rebuilt with the note's own environment (its 22 data files must be byte-identical to the note'spaper/data/at that commit); and the constantsNOTATETS_COMMIT,NOTATETS_KJERNE(3 sha256) andNOTATETS_FASIT(all 27fasit/files) inmodell/kontroll.py.kontrollanchors on those constants, not onKILDE.json, so updatingKILDE.jsonorfasit/alone makes it report a change. Then run the fullkontroll. A test fails if a core file does not match its sha256. No lint on the core. Changes to the model go inmodell/utvidelser/or in a user's working copy. - User-facing text (skills, docs, script messages) is Norwegian bokmål, plain and direct, with the note's terms (ledd, skranke, restanse, utnyttelse, saksbehandlingstid, ledet utenom, den koordinerte regelen). Code, comments and this file may be English.
- Facts in docs and skills are read from the code or the note, never from memory. Where they differ, the code wins.
- The note's core sentence is quoted verbatim: «Innsatsen for å håndheve lover og regler bør løpende stå i forhold til hvor mye, og hvor alvorlig, de faktisk brytes.» Short form: «Straffebud og strafferammer ligger fast.»
- Skill frontmatter has only
nameanddescription(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 variables in Bash. Skills write them literally into the command;kjor.pytreats an empty--dataor one containing${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
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 afterkontroll --raskon it has been run and its level told to the user. - Input to
diagnose/forlop:kjor.pyrejects unknown field names in aleddor instyring(exit 2, with a suggestion);merknad,kilde,kilderare allowed there, and top-level fields are not checked. - Scenarios: a changed base parameter stops the run unless the file sets
startlikevekt(kalibrerorubalanse); skills let the user choose and never pick. The models with a court queue drift slowly even without a shock (the note's own start is not an exact equilibrium);docs/forbehold.mdhas the numbers. - Exit codes of
kjor.py: 0 ok, 1 differences found bykontroll, 2 input or usage error (a coresys.exit("...")passes through as 2 with the message unchanged), 3 numpy/scipy missing.
Commands
- Development environment (versions pinned in
pyproject.toml, groupdev):python3 -m venv .venv && .venv/bin/pip install --group dev - Tests:
.venv/bin/pytest(about 2.5 minutes on the development machine, measured 2026-11-11);.venv/bin/pytest -m tregruns the note's full simulation (not timed). - Lint and types (the core is excluded in
pyproject.toml):.venv/bin/ruff check .and.venv/bin/mypy . - 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 ofsim.py). Six parts: core andfasit/against the note's checksums,diagnose,forlop, full run, extensions' limit cases, scenario runner againstfasit/data.--altshows every differing line instead of the first 40 per comparison. - 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 scenario eksempler/scenarioer/sjokkstorrelse_kjede.json --ut <scratch folder>(forlopandscenarioneed numpy and scipy;.venv/bin/pythonhas them) - Validate the plugin:
claude plugin validate . - Load the plugin locally:
claude --plugin-dir .
Workflow
- Remote is Forgejo (
git.fromaitochitta.com), never GitHub. Visibility, catalog entry and the move toopen/are the operator's decisions. PLAN.mdandSTATE.mdare local working files (gitignored).- Conventional Commits. Do not commit working documents.