Skip to content

Commit 460512c

Browse files
committed
docs: add Resolution order section to RFC-017
Spell out the topological resolution rule for inputs in an article. Covers why YAML order breaks on the alcoholwet/kieswet patterns, the graph edges drawn from `source.parameters`, `source.select_on[*].value`, and `temporal.reference`, and the cycle fallback behaviour. Pairs with the engine change on feat/foreach-implementation that implements the rule.
1 parent caa7fb3 commit 460512c

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

docs/rfcs/rfc-017.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,86 @@ When the input is named differently from the underlying column, `field` carries
173173
value: "0599"
174174
```
175175
176+
## Resolution order
177+
178+
Inputs in an article can reference each other through `$name` inside
179+
`source.parameters`, `source.select_on[*].value`, and
180+
`temporal.reference`. The engine resolves inputs in a **topological
181+
order** driven by those references, not in YAML order.
182+
183+
### Why topological, not YAML
184+
185+
Take the Rotterdam alcohol-licence article from poc-machine-law:
186+
187+
```yaml
188+
input:
189+
- name: leeftijd_exploitant
190+
source:
191+
regulation: wet_brp
192+
output: leeftijd
193+
parameters: {bsn: $bsn}
194+
- name: voldoet_aan_nationale_eisen
195+
source:
196+
regulation: alcoholwet/vergunning
197+
parameters:
198+
leeftijd_leidinggevende: $leeftijd_exploitant
199+
vloeroppervlakte: $vloeroppervlakte_horecalokaliteit
200+
type_bedrijf: $type_bedrijf
201+
- name: bsn
202+
source: {table: leidinggevenden, field: bsn, select_on: [{name: kvk_nummer, value: $kvk_nummer}]}
203+
- name: vloeroppervlakte_horecalokaliteit
204+
source: {table: inrichtingen, field: vloeroppervlakte_horecalokaliteit, select_on: [{name: kvk_nummer, value: $kvk_nummer}]}
205+
- name: type_bedrijf
206+
source: {table: inrichtingen, field: type_bedrijf, select_on: [{name: kvk_nummer, value: $kvk_nummer}]}
207+
```
208+
209+
`leeftijd_exploitant` references `$bsn`, but `bsn` is declared later.
210+
A strict YAML-order walk resolves `leeftijd_exploitant` first, sees
211+
`$bsn` as Null (lenient resolution returns Null for unknown names),
212+
and feeds a null BSN into the cross-law call, which returns garbage.
213+
`voldoet_aan_nationale_eisen` has the same problem against three later
214+
inputs. `kieswet/KIESRAAD-2024-01-01.yaml` shows the same pattern with
215+
`$verkiezingsdatum` as the last input of the article.
216+
217+
Law authors write inputs grouped by semantic cluster (all BRP inputs
218+
together, all licensing criteria together, all raw municipal table
219+
inputs at the bottom), not in dependency order. Forcing them to reorder
220+
by dependency makes the YAML less readable and ties the file to an
221+
implementation detail.
222+
223+
### Rule
224+
225+
Before resolving the inputs of an article, the engine computes a
226+
directed graph:
227+
228+
* Node per declared input.
229+
* Edge from `I` to `J` when `I` carries a `$J` reference in
230+
`source.parameters`, `source.select_on[*].value`, or
231+
`temporal.reference`, and `J` is the name of another input in the
232+
same article.
233+
* References to runtime parameters (names that match
234+
`execution.parameters`, not `execution.input`) are **not** edges.
235+
* Dot notation `$obj.field` creates an edge on the base name `obj`.
236+
237+
The engine resolves inputs in a topological order of this graph. When
238+
multiple orderings are legal, YAML order breaks ties so the trace
239+
output stays stable and predictable.
240+
241+
### Cycles
242+
243+
If the graph contains a cycle (input A references B references A, or
244+
an input references itself), the engine logs a warning via `tracing`
245+
and falls back to YAML order for the whole article. No panic, no
246+
hard error. This preserves the prior behaviour for malformed articles
247+
while making the failure visible.
248+
249+
### Host implications
250+
251+
Hosts that pre-resolve inputs before calling the engine (legacy path)
252+
must either resolve in the same topological order or let the engine do
253+
it. Hosts that register data sources and hand the parameters dict to
254+
`evaluate_law_output` get the correct behaviour automatically.
255+
176256
## Implementation notes
177257

178258
* The engine's data source registry already supports key-based lookup (`DictDataSource`). A new `RecordSetDataSource` adds multi-criteria filtering, field aliases, and array projection.

0 commit comments

Comments
 (0)