Derived Facts
Derived facts are context values computed on demand from other context values instead of being supplied as run input. A fact is resolved the first time a rule reads its key while it is absent, and — with forward-chaining inference on — re-derived automatically when an input it reads changes.
What a derived fact is
A normal context key is filled by a caller or written by an action. A derived fact is neither: you define how to compute it once, and the engine produces its value the moment a rule needs it. That keeps a definition in one place instead of copied across rules, and it lets a value exist only when it is actually used.
Two rules govern them: each key must be unique (“Derived fact keys must be unique”), and facts must not depend on each other in a cycle.
The Derived Facts tab
Derived facts are edited on the rule set editor's Derived Facts tab (the functions icon), which sits just before the Tests tab. Each fact has these fields:
| Field | Meaning |
|---|---|
| Key | Required and unique — the context key the fact fills. “Derived fact keys must be unique.” |
| Description | Optional note, up to 255 characters. |
| Value | A value source: Context, Env Var, Constant, or Expression. This is how the fact is computed. |
| Guard | Optional condition. “Always derived. Add a guard to only derive this fact when a condition holds.” |
When a guard is false If a fact has a guard and the guard does not hold, the key stays absent — the fact is simply not produced. Rules can test for that with the Is empty / Not empty operators, which is a clean way to branch on “did this fact apply?”.
Lazy resolution
A derived fact is resolved the first time a rule reads its key while the key is absent. Once resolved, the value is reused for the rest of the run. This works in both execution modes:
- Classic single-pass sets get lazy, on-demand resolution — including as a default for a missing input (define the fact for a key a caller may omit, and it fills in only when nothing was supplied).
- Inference sets additionally re-derive a materialized fact when one of its inputs changes, before the rules that read it are re-evaluated — so the cascade always sees an up-to-date value.
A fact can also be un-derived In an inference set, a fact that was resolved and later loses its footing is removed rather than left holding a stale value: its guard stops holding, or the values it reads go away. Only facts the engine itself computed are affected — a value you supplied with the run, or one a rule wrote over the top of, is never touched. See automatic retraction.
Chains and cycles
A fact's value or guard may reference other derived facts, and those chains resolve recursively: reading one fact can trigger the ones it depends on. What you cannot do is create a loop — if two facts depend on each other, the engine rejects it at save time with a message naming the cycle, so the problem surfaces while you author rather than at run time.
Common patterns
| Pattern | Example |
|---|---|
| Default for an optional input | Fact region = expression coalesce(ctx.region, "US"), so rules can read region whether or not the caller supplied one. |
| Shared business definition | Define isVip once (a guard or expression over tier and spend), then reference isVip from every rule instead of repeating the logic. |
| Computed value | Fact riskScore = an expression combining several context values into one number the rules compare against. |
| On-demand AI flag | Fact isAbusive with a guard using an AI-prompt operator, so the (billed) AI classification runs only when a rule actually reads the flag. |
Facts in a trace
When a run records a trace, its derived facts appear in a dedicated section — the key, whether it resolved lazily or eagerly, the iteration it was derived in, and the input keys it read. That gives you provenance: you can see exactly what a fact was computed from at the moment a rule used it. See Logs & Run History.
Prefer a derived fact when the value is a definition other rules read (“what does VIP mean here?”). Prefer an Add to Context action write when the value is a step in a flow that a specific rule produces on its way to a result.
Facts pull values; goals pull conclusions A derived fact answers “what is this value?” from other values, without firing a rule. Goal-driven evaluation answers “what would it take to establish this key?” and will fire rules to get there. In a goal-driven run the two work together: a goal that happens to be a derived fact is computed directly, no rule needed.