Recording what follows from a law as dated facts in a chronicle, built up step by step on vakantieverlof (Leerplichtwet 1969, art. 13a).
Chronolexography records each legal fact (an application, a decision, an objection) as a dated entry in the chronicle (kroniek) of the organization that establishes it. RFC-022 describes the model. This page lists what works today, one feature per section.
The running example is vakantieverlof: a parent asks the head of a school for leave outside the school holidays (Leerplichtwet 1969, art. 13a).
| Part | What it is | Where |
|---|---|---|
| Law | Art. 13a (the application, the decision and its test); Awb 4:2, 4:13, 3:46, 6:7 and 6:8 as hooks; Awb 7:11 (the objection and the decision on it) with 6:5, 6:9 and 7:10; the Regeling vaststelling schoolvakanties 2025–2030 | corpus/regulation/ |
| Policy | Fictitious school policy: the first school day (implements), the bounds of a school year, and the school’s own autumn and spring holidays | corpus/regulation/nl/uitvoeringsbeleid/ |
| Reduction | ”Did the head already grant leave this school year?”, “Does the leave fall outside the school holidays?” and “Where is the school established?”, over the school’s own chronicle | corpus/cells/obs_de_klimop/reducties/ |
| Stream | What an executogram of the school holds: where the school is established, since a day | corpus/cells/obs_de_klimop/executogrammen/ |
| Engine | Executes articles: hooks per stage, cross-law sources, open terms, data sources. Stores nothing | packages/engine |
| Cell | The school: keeps the chronicle, derives what it records, executes through the engine | packages/cel |
Recording the application (Cell::record_submission):
AANVRAAG item and of the Awb hooks on it.AANVRAAG.A submission may refer to a decision in the chronicle (refers_to, RFC-050). The cell then fills fields from that decision. A field of type decision gets the decision’s id. Every other field that the decision holds under the same name gets its value, which must fit the field. The submitter supplies neither.
Taking the decision (Cell::decide):
requests: leerplichtwet_1969#13a.source: {decisions: ...} input, and returns the value with its provenance.implements), and asks the cell for what its reduction fills. The head supplies what a hook asks for. Its findings come separately (findings), keyed by the id of the open term the law leaves to it (decided_per_case_by). Here these are the two judgements under art. 11 onder f and whether leave was already granted this school year. In the cell, the reduction fills that last one. The engine also gets the findings separately from the parameters, so a finding applies to every article in the decision that leaves the term to the head.BESCHIKKING that refers to the application. The head’s findings are among its fields. The chronolexogram does not store which findings the decision used. Cell::findings replays the decision and reads that from the engine’s report; a finding that a policy or the cell’s answer set aside is not among them.Cell::explain takes a recorded decision again with tracing, on its day and with the chronicle as it stood before it, and fails when the outcome differs. In its trace the cell’s answer within art. 13a is one node: the value, the reduction and its version, and how far the cell read its chronicle. Cell::explain_answer gives the cell’s own account of that answer: the reduction run again with tracing, with the decisions it counted and those its filter skipped. That trace is not stored.
decide returns a list of chronolexograms (Vec<Gram>). The decision comes first. After it comes each decision that the deciding article takes in turn: every output of type decision that is not null. They land in the chronicle together, or none do.
Recording without a submission (RFC-051): Cell::record_executogram records a fact of a stream the cell keeps, such as where the school is established. It refers to nothing, and records nothing when a value is missing or malformed.
Objecting: the same two steps under Awb 7:11, with record_submission and decide. The objection refers to the contested decision. The decision on it calls art. 13a anew. On revocation 7:11 gives the new decision, and the cell records that in the same append.
Law and policy say what is needed and how to compute it; they know no chronicle. A reduction is the only place that reads decisions, and it computes through law and policy again. Reduction takes place in the cell, as the position paper has it (“Reductie vindt altijd plaats ín de cel waar de betreffende chronolexogrammen zijn vastgelegd”). How the cell and the engine divide that work is in RFC-048 §3.
| Feature | Rulework | RFC |
|---|---|---|
| The application, with the Awb on it | Leerplichtwet 1969 art. 13a, Awb 4:2 and 4:13 | RFC-045 |
| The application in the chronicle | Leerplichtwet 1969 art. 13a, Awb 4:2 and 4:13 | RFC-046: chronolexography as a layer |
| The decision on the application | Leerplichtwet 1969 art. 13a, Awb 3:46, 6:7 and 6:8, fictitious school policy | RFC-047 |
| Once per school year | Leerplichtwet 1969 art. 13a lid 2, fictitious school policy, the school’s reduction | RFC-048 |
| The objection | Awb 6:5, 6:9, 7:10 and 7:11, Leerplichtwet 1969 art. 13a, the school’s reduction | RFC-050 |
| A second case: the parking card | BABW art. 49 and 51, Regeling gehandicaptenparkeerkaart art. 1, the Awb, fictitious municipal policy, the municipality’s reduction | RFC-045 to RFC-050 |
| Outside the school holidays | Leerplichtwet 1969 art. 11 onder f and 13a, the Regeling vaststelling schoolvakanties 2025–2030, the school’s holiday policy, its stream and two reductions | RFC-051 |
Article 13a says it establishes an application (AANVRAAG), what the application contains, and which decision it asks for. The Awb hooks onto every application, so submitting one also runs Awb 4:2 and 4:13. The fields of the application are the parameters its item lists plus those of the hooks. One exception: the parameter a hook names in produces.moment, here datum_ontvangst from Awb 4:13, is the moment of receipt and no field of the application.
produces.moment on Awb 4:13 marks receipt as the moment that counts.established_by: <regulation>#<article> limits a hook to the application of one article.Try it: just bdd, which runs corpus/regulation/nl/wet/leerplichtwet_1969/scenarios/vakantieverlof_aanvraag.feature
A cell, here a school, records the application as one chronolexogram in its chronicle. Chronolexography is an optional layer: it lives in packages/cel, and the law and the engine do not know it. The law names no fields for the record; the cell derives them from the keys above.
null when it can be absent. Otherwise it goes under missing, and the application is still recorded (Awb 4:5).moment holds the day of receipt. The cell fills it with the day of recording; that the two are the same day is the cell’s assumption.outputs. The outputs of art. 13a belong to the decision.recorded_on.{"__decimal": "0.3333333333333333333333333333"} with every digit, so it reads back as the same decimal and not as a float or an integer. The cell takes this encoding from the law model (regelrecht_law_model::stored, see law-model), so every store keeps and compares a value the same way. A supplied value may not hold that key; a supplied number is stored as the JSON it came in, and read back as the engine reads JSON: a whole number such as 5.0 as the integer 5. When the cell compares two stored values, for example a decision taken in turn against the decision value it came from, it uses the rule of the engine’s EQUALS on records. That rule lives in the same module. 5.0 and 5.00 are one value; an integer against a decimal of the same value is an error.The chronicle refuses a chronolexogram dated before the last one.
Try it: cargo test --manifest-path packages/cel/Cargo.toml
The head of the school decides on the application. Art. 13a is also that decision, a BESCHIKKING, and follows the Awb procedure. produces lists the application and the decision, each its own item. The application asks for this decision with requests, and the decision names its outputs:
The cell records the decision as a second chronolexogram that refers to the application.
implements), then from the head when deciding (decided_per_case_by). findings lists the fields that hold a finding of the head. The chronolexogram repeats neither the basis nor the source of a field or output: both follow from the law on recorded_on and from refers_to.verlof_verleend: false.Try it: just bdd, which runs vakantieverlof_besluit.feature, or cargo test --manifest-path packages/cel/Cargo.toml
The head grants leave “slechts eenmaal … per schooljaar” (art. 13a lid 2). Art. 13a declares the open term verlof_al_verleend_in_schooljaar, which is no field of the application. The head decides it per case (decided_per_case_by), and it has no default. How the head reads its own decisions back, the law does not say.
In a cell, a reduction fills the term with implements: rulework of the kind REDUCTIE, kept with the cell at corpus/cells/obs_de_klimop/reducties/. It finds the decisions taken under art. 13a and asks the school’s fictitious policy in which school year the asked leave falls.
bsn_jongere, eerste_verlofdag and verlof_verleend, and its id. A refusal does not count, nor a decision revoked on objection (see the objection).Cell::open, Cell::in_memory) and loads its reductions from reducties/ there, so it cannot be without them. A term that a reduction in that directory implements is the cell’s. On a day on which no reduction in force fills it, the cell refuses the decision. A school without reductions opens with a directory that has none.Cell::answers lists what the cell can answer: per version of each reduction, the open term it fills, the reduction’s $id and its valid_from. This list is a RegelRecht addition. In the Chronolexografie position paper a cell reduces its chronicle on request into a lexostatus, the answer that the cell’s facts give. The paper does not have a cell declare which lexostatussen it can answer; that idea comes from RFC-022 §4.1.decisions. Since schema v0.8.5 it may fill an open term (implements); it still has no hooks, overrides, execution.produces or open_terms. The corpus loaders leave it out; just validate checks it.fields. It is not a finding of the head, so a decision value leaves it out.Try it: just bdd, which runs vakantieverlof_besluit.feature with the head’s finding and schooljaargrenzen.feature next to the policy, or cargo test --manifest-path packages/cel/Cargo.toml
The parent objects to the decision. Awb 7:11 establishes the objection and decides on it, as art. 13a does for the application. The objection names the contested decision. The decision on it reconsiders that decision by calling its article again:
In a procedure, the article that decides gets the earlier steps as context: the objection and the decision it refers to, with their fields and findings. When 7:11 calls that decision anew (article: $bestreden_besluit), the call uses the decision’s own fields and findings. New findings come in from the top, and an article in the call must ask for them.
The cell records the objection with record_submission, referring to the contested decision. It fills bestreden_besluit from that reference and keeps it by its id:
taken_on). For both, that is 7:11.decide. The engine gets the contested decision as a decision value. For an admissible objection, 7:11 calls the decision anew: art. 13a runs with that decision’s fields and findings, under the law and policy of that day. decide passes what the head finds anew to the engine, separately from the parameters. A new finding wins over the decision’s own. A finding that no article asks for, such as one on a late objection, is an error. The engine asks the cell in that call, and the cell answers from the chronicle of that day without the contested decision. When an outcome of the decision item of art. 13a comes out different, the heroverweging gives cause, and 7:11 revokes the decision.nieuw_besluit holds the decision that art. 13a gave. The cell records it as a chronolexogram of its own under art. 13a, with its own period (Awb 6:7 and 6:8; for a decision on objection that is the period for appeal). The decision on the objection holds it by id. A second objection against the revoked decision is reconsidered, but the cell refuses to replace a decision twice. The revoked decision stays in the chronicle. The school’s reduction reads the decisions under 7:11 as a second input, and leaves out a grant that one of them revoked.The cell contains no Awb article. RFC-050 describes the design and what is still open.
Try it: just bdd, which runs corpus/regulation/nl/wet/algemene_wet_bestuursrecht/scenarios/bezwaar.feature, or cargo test --manifest-path packages/cel/Cargo.toml
The college of a municipality grants a gehandicaptenparkeerkaart on application (Besluit administratieve bepalingen inzake het wegverkeer, BABW, art. 49). The case runs on a cell of its own, built from the same packages/cel, without a change to the engine or the cell code. Only rulework and tests change.
What is the same:
decided_per_case_by on art. 49.reductie_geldige_gehandicaptenparkeerkaart, reads the college’s own decisions and fills an open term with implements. A refusal does not count, and neither does a decision that a decision on objection revoked.What differs:
source and passes the college’s judgements as parameters.aanvrager_heeft_geldige_gehandicaptenparkeerkaart. The college decides it per case, and it has no default. The reduction implements that term, so the engine asks the cell inside the policy. Because the term belongs to the policy and not to art. 49, the cell’s answer is no field of the decision. A replay reports it (Cell::explain), and Cell::explain_answer shows which card the reduction counted.derived, RFC-050). A heroverweging falls on a later day and would give a card that runs longer. That alone gives no cause, so an objection without merit against a grant leaves the grant and its date as they were.An applicant who fails the criteria is refused before art. 49 reads the college’s power, so the engine does not ask the cell. Asked to explain its answer for such a decision (Cell::explain_answer), the cell says it was not asked.
Not modeled: competence by place of residence (lid 1) and the CBR (lid 3), the institution (lid 2), the shorter validity of art. 51 lid 2 and 3, and the medical examination itself (Regeling art. 2). The judgements rest on that examination, but no rule checks that it took place or when it may be left out (Regeling art. 2 lid 2).
What the cell cannot do yet:
gemeente_code is not found, so the municipality’s policy is unscoped.Try it: just bdd, which runs the scenarios next to the BABW and the Regeling, or cargo test --manifest-path packages/cel/Cargo.toml --test parkeerkaart, or play it in the PoC app, where the visitor picks this case or vakantieverlof at the start (PoC portal)
Art. 11, onder f, exempts a child whose parent, by the specific nature of their profession, can go on holiday with the child “slechts buiten de schoolvakanties”. Art. 13a reads that as the open term verlof_valt_buiten_schoolvakanties, which the head decides per case. In the school’s cell no one has to: a reduction answers it from the law and from what the school recorded.
vestiging in corpus/cells/obs_de_klimop/executogrammen/vestiging.yaml. A move is a new executogram, and the region changes from its day.reductie_plaats_van_vestiging reads that stream (source: {executograms: vestiging}) and fills the open terms of art. 2 with the establishment in force on the leave days. It picks that one with combine: ONLY, which refuses two, so leave during which the school moves fails the decision. Art. 2 names no day; the cell passes on the leave days of art. 13a. reductie_verlof_valt_buiten_schoolvakanties asks the regeling for the region and the periods, asks the school’s policy for its own holidays (source: {regulation: ...}), and answers whether a leave day falls in any of the six holidays. When the regeling calls for the place of establishment inside that reduction, the cell answers there too.
Cell::explain_answer shows the Christmas holiday the reduction read.Not modeled: art. 7 and 8 of the regeling (the school’s extension of the summer by up to two days, the Wadden islands, the exemption by the minister) and a school with establishments in several regions.
Try it: just bdd, which runs regio_en_vakanties.feature next to the regeling and vakantierooster.feature next to the policy, or cargo test --manifest-path packages/cel/Cargo.toml --test schoolvakanties
An exploration into transparent, executable legislation, and one of the three projects in the starting selection of the Nederlandse Digitale Dienst.
GitHub repository
How it works
Stay informed
Roadmap (Dutch)
Documentation
Research
Nederlandse Digitale Dienst
Ministry of Economic Affairs and Climate Policy