ReferenceDecision records (ADRs)
ADR 0001: Expressions are a JSON tree of {op, args} nodes
Status: accepted
Status: accepted
Context
Rules need conditions that a browser, a JVM service and other runtimes evaluate identically. The candidates were JSON Logic, CEL, a vendor format (GoRules JDM) and our own small tree.
Decision
Conditions are a JSON tree: a literal, { "var": "data.amount" }, an operator call
{ "op": "lte", "args": [ ... ] } or a function call { "fn": "isBlank", "args": [ ... ] }, with a
fixed operator list per profile and strict typing. Function calls and host-supplied x- operators
were added later (ADR 0008); the shape did not change.
Why
- JSON Logic has the right idea and many ports, but its implementations disagree on truthiness
and edge cases; a community effort is under way to tighten the specification. Its shape,
{"<=": [a, b]}, puts the operator in the key, which plain JSON Schema cannot enumerate cleanly and OpenAI strict structured outputs cannot express at all. - CEL is typed, non-Turing-complete and has a conformance suite. It is a text language: a rule builder UI must parse and print it, and the TypeScript implementation was still marked beta when this was decided.
- A vendor format ties the contract to one company's roadmap.
{op, args}makes the operator a value. It validates with anenum, maps to sealed types in Java and discriminated unions in TypeScript, is trivially walkable for static checks, and a model can be constrained to produce it.
Consequences
- We own the semantics, so we own a conformance suite. That is the price, and it is paid in
conformance/. - JSON Logic remains reachable.
rulecheck jsonlogic import|exportconverts in both directions. The conversion is not purely mechanical, because JSON Logic converts types and Rule Cascade does not: the converter marks each construct as equivalent, as converted with a stated caveat, or as refused. The comparison and the full mapping are in JSON Logic and Rule Cascade. - Authors write more characters than in CEL. A text front end that compiles to the tree can be added later without changing the contract.