RFC-007 introduced hooks: articles that fire when another article’s produces annotation matches. This enables reactive execution: Awb 3:46 (reasoning requirement, motiveringsplicht) fires on any BESCHIKKING, Awb 6:7 (objection period, bezwaartermijn) fires on any BESCHIKKING, Awb 6:8 (start/einddatum) fires on any BESCHIKKING.
But an individual decision (beschikking) is not an instant computation. It is an administrative law (bestuursrecht) process that progresses through stages over time:
If hooks fire without awareness of lifecycle stages, all Awb obligations trigger at once, including Awb 6:8 (objection period date calculation), which needs bekendmaking_datum. But notification (bekendmaking) hasn’t happened yet at decision time. Treating a missing bekendmaking_datum as “skip this hook gracefully” is a workaround, not a design.
The problem: the decision and the notification (bekendmaking) are different moments in time, with different inputs, producing different outputs, governed by different articles of law. They must not fire in the same execution step.
The lifecycle of an individual decision (beschikking) is not defined by the Vreemdelingenwet or the Zorgtoeslagwet. It is defined by the Algemene wet bestuursrecht (Awb), the General Administrative Law Act. That is the purpose of the Awb: to define the general administrative procedure that all administrative bodies (bestuursorganen) follow, regardless of which specific law they are executing.
The Awb defines stages. Specific laws fill in the content at each stage. Other laws (Termijnenwet, KB gelijkgestelde dagen) hook into specific stages. This relationship already exists in law; it needs to be expressed in the schema.
In Awb terminology, what we describe here is a procedure, the objection procedure, the appeal procedure, the preparation procedure. The Awb never uses the word “lifecycle”; that is software engineering jargon.
However, in the Awb “procedure” typically refers to one phase (the objection (bezwaar) procedure, the appeal (beroep) procedure). The entire journey from application (aanvraag) to final/irrevocable (onherroepelijk) spans multiple procedures. In engineering, “lifecycle” captures this overarching concept: the full life of a decision (besluit) from birth (application) to final state (final/irrevocable (onherroepelijk), withdrawn (ingetrokken), or expired).
This RFC uses both terms deliberately:
procedure: in YAML): the domain term, used in the machine-readable specification because the YAML is a law specification and should speak the language of law.Both refer to the same thing: the Awb-defined sequence of stages that a decision (besluit) progresses through.
The Awb defines a lifecycle for administrative law (bestuursrecht) processes. This lifecycle is expressed in the YAML specification as a first-class construct. Laws do not define their own lifecycles; they declare which Awb-defined lifecycle they participate in through produces.
A lifecycle is a sequence of stages. Each stage:
AANVRAAG, BESLUIT, BEKENDMAKING)A single legal_character can have multiple procedure variants. Both a regular individual decision (beschikking) and a UOV (public consultation procedure) individual decision (beschikking) have legal_character: BESCHIKKING, but they follow different Awb procedures: the UOV omits objection (bezwaar) entirely (Awb 7:1 lid 1 sub d). Selecting the wrong procedure produces a legally invalid outcome.
The produces annotation gains an optional procedure_id field to disambiguate:
When procedure_id is omitted, the engine selects the default procedure for the legal_character. The Awb defines which procedure is the default.
The Awb defines procedures for BESCHIKKING as machine-readable constructs. Multiple procedures can apply to the same legal_character:
The diagram below shows the full individual decision (beschikking) lifecycle including parallel tracks. The main track (application (aanvraag) → appeal (beroep)) is strictly sequential. Three mechanisms can run in parallel: penalty payment (dwangsom, when the decision deadline (beslistermijn) expires), interim relief (voorlopige voorziening, after objection (bezwaar)/appeal (beroep)), and the administrative repair loop (bestuurlijke lus, within appeal (beroep)).
The applies_to in hooks (RFC-007) gains a stage field:
This is the key insight: hooks apply to the Awb’s lifecycle, not to the specific law’s decision (besluit). The Aliens Act (Vreemdelingenwet) produces a BESCHIKKING and thereby enters the Awb lifecycle. The Vreemdelingenwet does not know about Awb 6:8. Awb 6:8 does not know about the Vreemdelingenwet. They are connected through the lifecycle defined by the Awb.
A decision (besluit) progresses through the Awb lifecycle and accumulates outputs at each stage. The decision (besluit) itself is the state container; there is no separate “case” or “zaak” (case file) abstraction. This follows the Awb, which defines everything in terms of the decision (besluit).
When the engine executes a law that produces a BESCHIKKING:
Step 1: BESLUIT stage
Step 2: BEKENDMAKING stage (days/weeks later)
bekendmaking_datum is a genuine external event (the orchestration layer signals that notification (bekendmaking) has occurred). pasen_datum is also an external parameter, the computus algorithm is not in Dutch statute law, so the caller provides Easter Sunday’s date, consistent with the zero-domain-knowledge principle (RFC-007). Gelijkgestelde dagen (bridge days equated to public holidays) are resolved internally via IoC from harvested KB’s.
The engine yields between stages, returning:
The orchestration layer persists the decision (besluit) state and feeds new inputs when they become available.
The decision (besluit) state consists of:
| Component | What it is | Where it lives |
|---|---|---|
| Accumulated outputs | All outputs from completed stages | Decision (besluit) record |
| Current stage | Which lifecycle stage the decision (besluit) is at | Decision (besluit) record |
| Pending inputs | What external data is needed to advance | Derived from procedure definition |
| Contextual law | The lex specialis context for overrides | Set at creation, immutable |
| Parameters | Original parameters from the initial execution | Decision (besluit) record |
The engine itself remains stateless in the sense that it does not maintain decision (besluit) state internally. The decision (besluit) state is an external record (database row, event store, file) managed by the orchestration layer. The engine receives the decision (besluit) state as input and returns the updated state as output.
This is important: the engine is still a pure function per stage. But the composition of stages into a decision (besluit) lifecycle is now explicit, governed by the Awb lifecycle definition, and persisted externally.
Some stage transitions are automatic (engine computes the next stage’s outputs immediately). Others require external events:
| Transition | Type | Trigger |
|---|---|---|
| AANVRAAG → BEHANDELING | Automatic | Application (aanvraag) received |
| BEHANDELING → BESLUIT | Manual | Administrative body (bestuursorgaan) decides |
| BESLUIT → BEKENDMAKING | Manual | Notification (bekendmaking) sent |
| BEKENDMAKING → BEZWAAR | Automatic | Objection period (bezwaartermijn) starts |
The lifecycle definition distinguishes these: stages with requires fields that are not computable from previous outputs need manual input. The engine signals this by yielding with a description of what’s needed.
Conceptual correctness. The model matches the legal reality: a decision (besluit) is a process with stages, not an instant computation. The Awb defines the process, specific laws fill in the content.
Separation of concerns. Decision logic (Vreemdelingenwet) is separate from procedural logic (Awb lifecycle). Each law does what it’s supposed to do. The lifecycle connects them.
Temporal accuracy. Outputs are computed at the right moment. The objection period (bezwaartermijn) end date is calculated when the notification (bekendmaking) happens, not when the decision (besluit) is made. The feestdagenkalender uses the correct year for the notification (bekendmaking) date, not the decision (besluit) date.
Auditability. The decision (besluit) record shows exactly what happened at each stage, when, and with what inputs. This supports the reasoning requirement (motiveringsplicht, Awb 3:46) and provides a complete administrative trail.
Extensibility. New lifecycle stages can be added by the Awb without changing specific laws. New hooks can bind to any stage. The lifecycle is data (YAML), not code.
Real-world fidelity. The model naturally handles long-running processes (asylum decisions that take months), manual steps (administrative body (bestuursorgaan) investigation), and asynchronous events (notification (bekendmaking) by post).
Complexity. The engine moves from “pure function” to “state machine executor.” The orchestration layer must now manage decision (besluit) state persistence. This is a lot of implementation work.
Backward compatibility. Existing laws that produce BESCHIKKING without a lifecycle still work; they complete in a single stage. But new laws should use the lifecycle model. RFC-007 hooks without stage default to BESLUIT for backward compatibility.
State management. Decision (besluit) state must be persisted somewhere. The engine doesn’t dictate where (database, event store, file system), but the orchestration layer must handle it.
Alternative 1: Implicit stages via parameter presence
bekendmaking_datum is absent.Alternative 2: Multiple explicit executions (no lifecycle)
bekendmaking_datum.Alternative 3: Event sourcing / CQRS
Case aggregate with event sourcing.The procedure is a new top-level construct in the schema (procedure: key), defined at the law level (not article level). It references stages, and hooks reference stages.
The engine needs:
(legal_character, procedure_id) → procedure_definition, loaded from Awb YAML. When procedure_id is omitted in produces, selects the procedure marked default: true.find_hooks gains a stage parameter. Hooks without stage default to BESLUIT.The decision (besluit) state is not stored in the engine. It is passed in by the caller and returned with updates. The engine remains a library, not a service.
Schema version: The procedure: top-level key and the procedure_id field on produces are new constructs not present in schema v0.4.0. They land in schema v0.5.0 (see the Schema Reference version history), alongside the hooks and overrides from RFC-007. Awb YAML files using procedure: must reference v0.5.0 or later.
Yield mechanism. The largest architectural change is the yield mechanism. The current engine returns Result<ArticleResult>, a terminal result. Multi-stage execution needs the engine to return either a completed result or a “yielded” state waiting for input to proceed to the next stage. Two implementation approaches:
enum ExecutionOutcome { Complete(ArticleResult), Yielded(StageState) }, replaces Result<ArticleResult> at the stage execution boundary. StageState carries accumulated outputs, current stage, and required inputs for the next stage.execute_stage alongside the existing evaluate_article_with_service. The existing method remains unchanged for single-stage laws; execute_stage handles lifecycle-aware execution.Decision (besluit) state is external (passed in, returned out), which is compatible with the stateless engine design. The engine uses &self (immutable borrows) for execution, so there is no architectural conflict with multi-stage execution, each invocation is still a pure function over its inputs.
Nested lifecycle recursion. A decision on objection (besluit op bezwaar) is itself a decision (besluit), creating recursive nesting. The engine’s cycle detection (ResolutionContext.visited) operates within a single invocation; cross-invocation nesting is the orchestration layer’s responsibility. The engine should provide a max_nesting_depth configuration to help the orchestration layer detect excessive recursion. In practice the Awb chain is naturally finite (individual decision (beschikking), decision on objection (besluit op bezwaar), appeal (beroep), higher appeal (hoger beroep)), but a configurable depth limit provides a safety net.
Do all decisions (besluiten) share the same lifecycle? Resolved: No. Each legal_character has its own lifecycle, defined by the relevant Awb chapters. A BESCHIKKING has application (aanvraag) → processing (behandeling) → decision (besluit) → notification (bekendmaking) → objection (bezwaar). A BESLUIT_VAN_ALGEMENE_STREKKING (general rule, besluit van algemene strekking) has a different procedure (Awb afdeling 3.4, Staatscourant publication, no objection (bezwaar), direct appeal (beroep)). The Awb defines these different procedures, the lifecycle definition in YAML follows the Awb structure per type.
Nested lifecycles. Resolved: An objection (bezwaar) is itself a decision (besluit, Awb 7:12), which starts its own lifecycle (with its own notification (bekendmaking), and possibility of appeal (beroep) before the administrative court (bestuursrechter)). The engine applies the same lifecycle pattern recursively, a decision on objection (besluit op bezwaar) enters the Awb lifecycle just like the original individual decision (beschikking). If a law inadvertently creates infinite recursion, that is a defect in the law, not in the engine.
Note that RFC-007’s cycle detection does not cover this case. RFC-007 detects cross-law circular references within a single engine invocation (Law A → Law B → Law A). Nested lifecycle recursion (individual decision (beschikking) → decision on objection (besluit op bezwaar) → its own objection (bezwaar) → …) happens across separate engine invocations initiated by the orchestration layer. The orchestration layer is responsible for detecting excessive lifecycle nesting depth, not the engine. In the Awb this chain is naturally finite (individual decision (beschikking) → decision on objection (besluit op bezwaar) → appeal (beroep) → higher appeal (hoger beroep) terminates), but the orchestration layer should enforce a configurable maximum nesting depth as a safety measure.
Parallel stages. Resolved: The main lifecycle track (application (aanvraag) → processing (behandeling) → decision (besluit) → notification (bekendmaking) → objection (bezwaar) → appeal (beroep)) is strictly sequential, each stage depends on completion of the previous one. However, three genuinely parallel tracks can be spawned from the main lifecycle:
Additionally, two alternative paths exist as branches (not parallelism): direct appeal (rechtstreeks beroep, Awb 7:1a, skipping objection (bezwaar)) and the uniforme openbare voorbereidingsprocedure (Awb afdeling 3.4, replacing regular preparation with public consultation and eliminating objection (bezwaar)). The administrative repair loop (bestuurlijke lus, Awb 8:51a-8:51d) is a loop within appeal (beroep), not a parallel track, the administrative court (bestuursrechter) suspends appeal (beroep), the administrative body (bestuursorgaan) repairs the defect, then appeal (beroep) resumes. See Appendix A for the full procedure analysis and Appendix B for Mermaid state diagrams.
Decision deadline (beslistermijn) enforcement. Resolved: The decision deadline (beslistermijn) is calculated by a hook at the AANVRAAG stage, Awb 4:13 provides the default (“redelijke termijn”), specific laws override via lex specialis (same pattern as bezwaartermijn_weken). The engine does not enforce the deadline: if besluit_datum exceeds the decision deadline (beslistermijn), the engine continues normally but annotates the decision (besluit) with a warning. Exceeding the decision deadline (beslistermijn) does not invalidate the decision (besluit), it expands the lifecycle with new available paths for the interested party (belanghebbende): notice of default (ingebrekestelling, Awb 4:17), penalty payment (dwangsom, Awb 4:18), and appeal (beroep) against failure to decide in time (Awb 6:2 lid 1 sub b). These are modeled as conditional branches in the lifecycle state machine.
Withdrawal (intrekking) and revocation. Resolved: Withdrawal (intrekking, Awb 10:4-10:5) is a state transition in the original decision (besluit)‘s lifecycle, not a separate lifecycle. An individual decision (beschikking) continues to exist after notification (bekendmaking), it can be final/irrevocable (onherroepelijk), withdrawn (ingetrokken), amended, or expired. The withdrawal (intrekking) itself is a nested decision (besluit, same pattern as question 2): it requires motivation, notification (bekendmaking), and can be challenged via objection (bezwaar). The original individual decision (beschikking)‘s state changes as a consequence of the withdrawal (intrekking) decision completing its own lifecycle.
| Stage | Awb Articles | Description |
|---|---|---|
| AANVRAAG | 4:1-4:6 | Belanghebbende submits application. Must include name, address, date, indication of requested decision (4:2). |
| ONTVANGSTBEVESTIGING | 4:3a | Bestuursorgaan confirms receipt. |
| AANVULLING | 4:5 | If application is incomplete, bestuursorgaan gives opportunity to supplement. Can refuse to process if not supplemented. |
| BEHANDELING | 3:2, 4:7-4:12 | Investigation phase. Includes duty to hear applicant before rejection (4:7-4:8), advisory opinions (3:5-3:9). |
| BESLISTERMIJN | 4:13-4:15 | Decision must be made within statutory deadline, or within “reasonable period” (max 8 weeks). Can be extended with notification (4:14). Suspension possible when applicant must supplement (4:15). |
| BESLUIT | 1:3 | Bestuursorgaan takes the decision. Must include motivation (3:46-3:50). |
| BEKENDMAKING | 3:40-3:44 | Decision is communicated to applicant (by mail/delivery for beschikking). |
| Stage | Awb Articles | Description |
|---|---|---|
| INGEBREKESTELLING | 4:17 | If decision is late, applicant sends written notice of default. |
| DWANGSOM_LOOPT | 4:17 lid 1-3 | After 2 weeks from ingebrekestelling: dwangsom starts. EUR 23/day (days 1-14), EUR 35/day (days 15-28), EUR 45/day (days 29-42). Max 42 days. |
| DWANGSOMBESLUIT | 4:18 | Bestuursorgaan determines liability and amount within 2 weeks after last dwangsom day. This is itself a besluit, subject to bezwaar/beroep. |
This is a parallel track: the ingebrekestelling can be sent while BEHANDELING is still ongoing (once the beslistermijn has expired). The dwangsom runs concurrently with the ongoing decision procedure.
| Stage | Awb Articles | Description |
|---|---|---|
| BEZWAARTERMIJN | 6:7-6:8 | 6 weeks from day after bekendmaking. |
| BEZWAAR_INGEDIEND | 6:4-6:6 | Belanghebbende files bezwaarschrift with the bestuursorgaan. |
| ONTVANKELIJKHEIDSTOETS | 6:5-6:6 | Check: on time? Against a besluit? By belanghebbende? If manifestly inadmissible: can skip hearing (7:3 sub a). |
| HOREN | 7:2-7:9 | Hearing of bezwaarmaker and other belanghebbenden. Documents available 1 week before (7:4). Can be skipped in limited cases (7:3). |
| HEROVERWEGING | 7:11 | Full reconsideration of the original decision on its merits (“ex nunc”). |
| BESLUIT_OP_BEZWAAR | 7:12 | New decision replacing (or confirming) original. Must be motivated. Decision within 6 weeks (or 12 weeks with advisory committee, 7:10). |
| BEKENDMAKING_BOB | 3:41 | Besluit op bezwaar is communicated. Starts new beroepstermijn. |
| Stage | Awb Articles | Description |
|---|---|---|
| BEROEPSTERMIJN | 6:7-6:8 | 6 weeks from day after bekendmaking of besluit op bezwaar. |
| BEROEP_INGEDIEND | 8:1 | Appeal filed with competent bestuursrechter. |
| VOORONDERZOEK | 8:27-8:45 | Court investigation: exchange of documents, possible expert opinion. |
| ZITTING | 8:56-8:65 | Court hearing. |
| UITSPRAAK | 8:66-8:77 | Court judgment: gegrond/ongegrond. Can annul decision, instruct new decision, or apply bestuurlijke lus. |
| Stage | Awb Articles | Description |
|---|---|---|
| HOGER_BEROEP | 8:104-8:108 | Appeal to Afdeling bestuursrechtspraak Raad van State, Centrale Raad van Beroep, or College van Beroep voor het Bedrijfsleven (depending on law area). 6 weeks. |
The voorlopige voorziening is the most important parallel track:
The bestuurlijke lus is a loop within the beroep phase, not a parallel track.
The UOV applies when a specific law prescribes it, or when the bestuursorgaan voluntarily chooses to apply it (3:10). Common for: environmental permits, spatial planning decisions, complex infrastructure.
| Stage | Awb Articles | Description |
|---|---|---|
| AANVRAAG | 4:1 | Same as regular procedure. |
| ONTWERP_BESLUIT | 3:11 | Bestuursorgaan prepares draft decision and makes it available for inspection. |
| TER_INZAGE | 3:11-3:14 | Draft and supporting documents available for 6 weeks. Published in Staatscourant/gemeenteblad. |
| ZIENSWIJZEN | 3:15-3:17 | Anyone (not just belanghebbenden) can submit views during the 6-week period. Oral or written. |
| BESLUIT | 3:18 | Final decision, taking zienswijzen into account. Must respond to zienswijzen in motivation (3:46). |
| BEKENDMAKING | 3:41-3:44 | Decision published. |
When the UOV applies, bezwaar is excluded (7:1 lid 1 sub d). Rechtsbescherming goes directly to beroep.
A besluit van algemene strekking (e.g., verordening, beleidsregel, ministeriele regeling) has a fundamentally different lifecycle:
| Stage | Articles | Description |
|---|---|---|
| VOORBEREIDING | Various | May include UOV (afdeling 3.4), consultation rounds, internet consultation, advisory bodies (e.g., Raad van State for wetten/AMvB). |
| VASTSTELLING | Organic law | Decision-making body adopts the regulation (gemeenteraad, minister, etc.). |
| BEKENDMAKING | 3:42 | Publication in official gazette: Staatscourant (ministeriele regelingen), Staatsblad (wetten/AMvB), gemeenteblad/provincieblad (decentraal). |
| INWERKINGTREDING | Various | Effective date, usually specified in the regulation itself or per KB. |
Key differences from beschikking: no aanvraag (not applied for by belanghebbende), no bezwaar (Awb 8:3 lid 1 sub a excludes bezwaar/beroep against AVVs), no individual bekendmaking (publication in official gazettes), rechtsbescherming only via exceptieve toetsing.
| BAS Sub-type | Bezwaar? | Beroep? | Example |
|---|---|---|---|
| Algemeen verbindend voorschrift (AVV) | No | No (8:3) | Wet, AMvB, verordening |
| Beleidsregel | No | No (8:3) | Beleidsregel toeslagen |
| Concretiserend BAS | No bezwaar | Yes (direct beroep) | Bestemmingsplan, verkeersbesluit |
An exploration by Bureau Architectuur of the Dutch Ministry of the Interior into the possibilities of transparent, executable legislation.
Bureau Architectuur
Ministry of the Interior and Kingdom Relations