- Rust 65.1%
- JavaScript 16.5%
- Vue 13.5%
- Gherkin 2%
- Python 0.8%
- Other 2%
* docs: RFC-022 uitkleden en implementatieplan naar RFC-025
RFC-022 was met 497 regels veruit de grootste RFC in de repo (bijna 2x
de eerstvolgende). Teruggebracht tot een scherpe architectuur-RFC:
- implementatieplan (fasering, affected-components-tabel, schema-bump
v0.6.0) en de RFC-007/009/013-amendments verplaatst naar de nieuwe
RFC-025, zodat RFC-022 een architectuurbeslissing blijft en niet een
bouwplan
- de drie-assen-uitleg (cell / competent_authority / security context)
stond vier keer volledig uitgeschreven; ontdubbeld naar een canonieke
uitleg in paragraaf 2
- paragraaf 3.2 (extensions/blauwe_knop) van vier vrijwel identieke
mini-essays teruggebracht tot twee kernpunten; validatiedetails naar
het CJIB-voorstel en RFC-025
- losse bezwaarbaar-paragraaf in Context geschrapt (stond al als
Alternative 7)
De voorbeelden vertellen nu een doorlopend CJIB-verhaal: de
payments_received chronicle-stream, zijn events, de BETALINGSVERPLICHTING
-decretograms en de openstaande_vorderingen-lexostatus delen dezelfde
identifiers. Een decision_type-mapping (Wahv/OM/AP) verankert de drie
nieuwe waarden in herkenbare casus.
Alle paragraafnummers die het CJIB-voorstel en RFC-008 aanhalen blijven
behouden; docs-build slaagt.
* docs: reviewbevindingen RFC-022/025 verwerken
- kwijtschelding_verleend-event hangt nu aan een zustertstroom op
dezelfde cjib_main_chronicle in plaats van aan de payments_received
-stroom (die alleen een payment_received-event toont)
- recognizable -> recognisable en optimization -> optimisation,
consistent met de Britse -ise-schrijfwijze in het RFC-corpus
* docs: RFC-025 schrappen, implementatieplan vervalt
Het losse implementatieplan (RFC-025) is niet nodig; de normatieve
regels die ertoe deden (load-time shadowing-error, experimental-gate,
warn-not-reject-validator) staan al volledig in RFC-022 zelf. RFC-025
verwijderd en de verwijzingen ernaar in RFC-022 vervangen door
zelfstandige formuleringen, zodat RFC-022 op zichzelf klopt. De open
RFC-009 key-reuse security-vraag blijft in de Context behouden.
* docs: RFC-025-verwijzingen uit RFC-022 verwijderen
Volgt op het schrappen van RFC-025: de negen verwijzingen naar het
verwijderde implementatieplan vervangen door zelfstandige formuleringen,
zodat RFC-022 geen dode links meer bevat en op zichzelf klopt. De open
RFC-009 key-reuse security-vraag blijft in de Context behouden.
* docs: reviewbevindingen vijandige RFC-022-review verwerken
Naar aanleiding van een multi-agent vijandige review (paper-trouw,
minimaliteit, coherentie, juridisch):
- §3.2: dode normatieve claim gerepareerd. De "closed-enum, validated
field"-bewering delegeerde naar mechaniek die met RFC-025 was
geschrapt; afgezwakt tot een runtime-gevalideerd veld met
route-bewuste guard, zonder verwijzing naar niet-bestaande grondslag.
- §1.2: transactionele-consistentie-invariant (I14) toegevoegd als
tegenhanger van elementariteit ("wat tegelijkertijd ontstaat wordt
samen vastgelegd", voorkomt multirealiteit); de enige bevestigde
paper-trouw-lacune.
- RFC-003 dangling reference opgelost (toegevoegd aan depends_on en
References).
- Juridische precisie: Awb-bezwaartermijn-duur is 6:7 (aanvang 6:8);
Wahv vervangt de Awb-rechtsgang door een lex-specialis-regime in
plaats van "disapplies bezwaar"; scope-grens verduidelijkt dat een
OM-schadevergoeding (Wet OM-afdoening) wel een STRAFBESCHIKKING is.
- Kleinere opschoningen: intake-veld geduid, §3-intro aangescherpt,
twee YAML-voorbeelden ingekort, cross-kroniek-ordening verduidelijkt
als within-cell.
|
||
|---|---|---|
| .claude | ||
| .github | ||
| conformance | ||
| corpus | ||
| dev | ||
| docs | ||
| features | ||
| frontend | ||
| frontend-lawmaking | ||
| packages | ||
| schema | ||
| script | ||
| tests/fixtures/federation | ||
| .dockerignore | ||
| .env.example | ||
| .env.sso-local.example | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| .yamllint | ||
| CLAUDE.md | ||
| corpus-registry.yaml | ||
| deny.toml | ||
| docker-compose.dev.yml | ||
| Justfile | ||
| LICENSE | ||
| README.md | ||
| REVIEW.md | ||
| rust-toolchain.toml | ||
regelrecht
Machine-readable Dutch law execution. regelrecht takes legal texts, encodes them as structured YAML, and runs them as deterministic decision logic.
What does it do
- The engine takes a regulation and a set of inputs, evaluates the decision logic, and returns a result with a full explanation trail
- Laws are tested against real-world scenarios using BDD (Gherkin) tests, many derived from legislative explanatory memoranda
- A harvester downloads and tracks Dutch legislation from the official BWB repository
- Regulations can be edited through a web UI with live execution preview
Components
Rust packages
| Package | Description |
|---|---|
| packages/engine/ | Law execution engine (also compiles to WASM) |
| packages/harvester/ | Downloads Dutch legislation from BWB |
| packages/pipeline/ | PostgreSQL job queue for law processing |
| packages/admin/ | Admin dashboard API (Axum) |
| packages/editor-api/ | Backend API for the law editor |
| packages/corpus/ | Git integration for the regulation corpus |
| packages/shared/ | Shared domain types across crates |
| packages/tui/ | Terminal dashboard (Ratatui) |
Frontends and sites
| Directory | Description |
|---|---|
| frontend/ | Law editor UI (Vue 3 + Vite) |
| frontend-lawmaking/ | Law-making process visualization (Vue 3 + Vite) |
| docs/ | Astro site: landing page + documentation |
Data and testing
| Directory | Description |
|---|---|
| corpus/regulation/ | Dutch regulations in machine-readable YAML |
| schema/ | Versioned JSON schema for the law format (current: v0.5.2) |
| features/ | Gherkin BDD scenarios for law execution |
| packages/grafana/ | Grafana monitoring dashboards |
Deployed services
| Service | URL |
|---|---|
| Editor | https://editor.regelrecht.rijks.app |
| Landing page | https://regelrecht.rijks.app |
| Documentation | https://docs.regelrecht.rijks.app |
| Law-making | https://lawmaking.regelrecht.rijks.app |
| Harvester admin | https://harvester-admin.regelrecht.rijks.app |
| Grafana | https://grafana.regelrecht.rijks.app |
PR preview environments are deployed automatically and cleaned up when the PR is closed.
Getting started
Prerequisites: Rust (stable) and just.
just check # run all quality checks (format, lint, build, validate, tests)
just test # unit tests only
just bdd # BDD tests only
Faster builds (recommended)
Run just dev-setup once. It does three things:
- Points every worktree at one shared target dir — a new worktree reuses the already-built dependency graph instead of cold-building ~600 crates.
- Puts that target on fast local storage when the repo lives on a slow mount.
A Rust build writes tens of thousands of small files; on a 9p/NFS/SMB mount
(e.g. a WSL2 or Docker-Desktop dev container where the repo is a Windows
drive) that I/O dominates build time — often more than everything else
combined.
dev-setupdetects this and relocates the target to~/.cache/regelrecht/(local disk). This is usually the single biggest win. - Installs mold +
sccache. mold (wired intopackages/.cargo/config.toml) speeds up linking and is a hard requirement for the dev recipes;sccacheis installed but left off locally.
sccache is disabled locally because it requires CARGO_INCREMENTAL=0 and so
disables incremental compilation — which hurts the just dev edit-rebuild loop.
Enable it only for cold or flag-varying builds:
export RUSTC_WRAPPER=sccache CARGO_INCREMENTAL=0
CI uses both mold and sccache (see .github/workflows/ci.yml).
Running a dev stack
just dev # full native dev stack (admin + both frontends + grafana/prometheus)
just dev-frontend # all frontends (editor 7300, admin 7400, lawmaking 7500), no observability
just dev-frontend editor # just the editor (editor-api + editor UI + DB)
just dev-frontend admin # just the admin API + admin UI + DB
just dev-frontend lawmaking # just the lawmaking UI (no backend)
just dev-down # stop whichever of the above is running
dev-frontend with no argument starts every frontend; pass editor, admin,
or lawmaking to start just one. Either way it starts only the components those
frontends need — no grafana, prometheus, or workers. The editor runs with real
SSO against the central
Keycloak, so it needs .env.sso-local (copy .env.sso-local.example). It and
just dev are mutually exclusive (they share .dev-pids and ports) — run one at
a time.
Vite ports default to 7300/7400/7500 (overridable via EDITOR_PORT /
ADMIN_FE_PORT / LAWMAKING_PORT). When a native backend can't reach Postgres
on localhost (e.g. a WSL2/Docker-Desktop dev container, where Postgres is
published on the Docker host), point it at host.docker.internal: for the
admin / just dev paths set DB_HOST=host.docker.internal in .env; for the
editor that host comes from DATABASE_URL in .env.sso-local (the
.env.sso-local.example already uses host.docker.internal).
See the docs site for full development instructions.