Table of Contents

The rule document format

A rule document is one of three things: a single rule, a rule set, or a decision table. Every object in it has a closed set of keys, so an unknown key is a validation error, not something silently ignored.

The formal contract is a JSON Schema (draft 2020-12): download rule-schema.json. engine.Validate is the authority: it also checks what a schema can't express, such as unique ids and whether a regular expression compiles.

Document shapes

The root has It is Loads as
id and condition a single rule a rule set of one rule
rules a rule set a rule set
decisionTable a decision table a rule set, one rule per row

Rule set

Key Required Type Meaning
rules ✓ array of rules At least one rule. Ids must be unique.
name string For people. Surfaces as RuleSet.Name.
description string For people. Ignored by the engine.
stopAfterFirstMatch boolean Stop after the first rule whose condition holds. false by default.
params object Named expressions every rule may reference. See Scoped params.

Rule

Key Required Type Meaning
id ✓ string Unique in the set. Reported in results, traces and errors.
condition ✓ condition A group or a leaf.
actions array of actions Applied when the condition holds. May be empty or absent.
else array of actions Applied when the condition doesn't hold.
priority integer Higher runs first. 0 by default; ties keep document order.
enabled boolean false skips the rule entirely. true by default.
failureMessage string Non-empty. Surfaces on result.Failures when the rule is evaluated and its condition doesn't hold. Excluded from the content hash.
params object Named expressions for this rule only, shadowing the set's on a name collision. See Scoped params.
description string For people. Ignored by the engine.
layout any For visual editors. Ignored by the engine and excluded from the content hash.

Condition group

Key Required Meaning
type ✓ Always "group".
operator ✓ AND or OR (one or more children), or NOT (exactly one).
rules ✓ The child conditions.

Condition leaf

Key Meaning
operator Required. One of the condition operators.
field A dotted path into the fact, or "$" inside a quantifier.
expression A computed left-hand side, in place of field.
value The comparison value. Required, forbidden or free-form depending on the operator.
name The function name, for custom only.
condition The element condition, for Any, All and None only.

A leaf has field or expression, not both. custom and the quantifiers take field only.

Condition operators

Operator value
Equals, NotEquals a scalar or null
GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual a scalar
Contains, StartsWith, EndsWith a string
MatchesRegex a valid regular expression
In, NotIn a non-empty array of non-null scalars
IsNull, IsNotNull none
custom whatever the function named in name expects, or none
Any, All, None none: condition instead

Conditions explains each, and what each does with a null.

Action

Key Required Meaning
type ✓ setOutput, addToOutput, appendToOutput, removeOutput, or a custom action type the engine registered.
target ✓ The output name.
value see meaning A scalar or an expression. Required for the built-in writers, forbidden for removeOutput, optional for a registered custom type (the handler then sees null).

Expression

One of:

Shape Example
a bare scalar 0.1
{ "literal": <scalar> } { "literal": "gold" }
{ "field": "<path>" } { "field": "Order.Total" }
{ "op": "<operator>", "operands": [ … ] } { "op": "add", "operands": [ 1, { "field": "Order.ItemCount" } ] }
{ "call": "<value function>", "operands": [ … ] } { "call": "RoundTo", "operands": [ { "field": "Order.Total" }, 2 ] }
{ "param": "<name>" } { "param": "averageLine" }
op Operands
add, multiply, concat, coalesce 2 or more
subtract, divide, modulo exactly 2
negate, count exactly 1

A call names a value function the engine registered; operands is optional (a no-argument call), and a function that declares a required operand count gets calls arity-checked at load. A param references a scoped param in scope, and is not valid inside a quantifier's element condition. Computed values has the semantics.

Scoped params

params maps names to expressions. The set's params are visible to every rule; a rule's are visible to that rule and shadow the set's on a name collision; a decision table may carry params for its then cells. Definitions may reference sibling and outer params, but never cyclically — a cycle is a validation error at the offending definition. References are inlined at load, so params never change what a rule computes, only how the document reads; a param-authored document gets the same content hashes as its hand-inlined twin. Scoped params is the guide.

Decision table

{ "decisionTable": { "id": "…", "hitPolicy": "first", "inputs": [ … ], "outputs": [ … ], "rows": [ … ] } }
Key Required Meaning
inputs ✓ Columns of conditions: { "field": "…", "operator": "…" }. operator defaults to Equals.
outputs ✓ Columns of actions: { "target": "…", "type": "…" }. type defaults to setOutput and may name a registered custom action; removeOutput isn't allowed.
rows ✓ { "when": [ one cell per input ], "then": [ one cell per output ] }.
hitPolicy collect (default) or first.
params Named expressions the then cells may reference. See Scoped params.
id The prefix of the generated rule ids: <id>-0, <id>-1, …, or row-0, row-1, … when omitted.
name, description For people.

A null when cell is a wildcard, and a null then cell writes nothing. Decision tables has worked examples.

Known differences between the schema and the engine

  • Extra keys on an expression object. The schema rejects a key it doesn't know on an expression ({ "field": "Order.Total", "note": "…" }); the engine's validator decides an expression's kind from op, field or literal and ignores any other key. Documents that pass the schema always load.