What is a Dry Run?
A Dry Run tests how your rules evaluate a single set of input facts against a specific policy version — without any side effects. No execution logs are written, no integrations are called, and no quotas are consumed. Think of it as a unit test for your rules.Dry Run vs Impact Simulation: A Dry Run tests one input at a time for quick validation. Impact Simulation tests a version against hundreds or thousands of historical inputs and compares the results against a baseline version. Use Dry Runs for iterative development; use Impact Simulation for regression testing before deployment.
When to Use Dry Run
- After creating or modifying rules — verify they match expected inputs
- Before publishing a DRAFT version — your safety net
- When debugging unexpected execution results — reproduce the scenario
- When comparing two versions with the same input (Dry Run Compare)
Running a Dry Run
Console
Navigate to a policy version → Dry Run tab → enter input facts → click Run.CLI
| Flag | Description |
|---|---|
--debug | Include execution traces and decision traces in the response |
--mock | Mock external integration calls (webhooks, notifications, etc.) |
API
Response
State Layers
Thedata object exposes three layers of state explicitly — never merged into a single blob:
inputFacts— facts as received from the request, normalized.mutatedFacts— only the facts whose values were changed by rule actions.generatedVariables— variables created by rule actions that did not exist in the input. This includes per-action change keys like{refVar}__delta(signed change fromMUTATE_FACT) and{targetVar}__delta(non-negative increment fromINCREMENT_FACT).
{ ...inputFacts, ...mutatedFacts, ...generatedVariables }. Keeping them separate makes audits, replays, and debugging deterministic — you always know which value originated where.
Execution Traces
Each rule that the engine evaluated produces one execution trace. The trace records the exact match expression that was checked, the input facts the rule saw, and the actions it generated:tenantId, policyGroupId, policyVersionId, ruleId) make every trace self-locating — you never need an external lookup to know which tenant, group, version, and rule produced it.
Decision Traces
While execution traces record what was evaluated, decision traces record what was selected. Each rule appears indecisionTraces with its final status and the reason code that produced it:
status | Meaning |
|---|---|
SELECTED | Rule won and its actions were applied |
NO_MATCH | Rule’s condition evaluated to false |
NOT_SELECTED | Pre-competition filter (e.g., effective date — reserved for future) |
BLOCKED | Lost mutex or activation group competition (reasonCode specifies scope) |
ERROR | Action execution failed |
reasonCode | When it appears |
|---|---|
FINAL_WINNER | Rule was selected as the winner |
CONDITION_MISMATCH | Input did not satisfy the condition |
EFFECTIVE_DATE_INVALID | Outside the rule’s effective date window (reserved) |
MUTEX_PRIORITY_LOST | EXCLUSIVE mutex (limit=1) — another rule had higher priority/score |
MUTEX_LIMIT_REACHED | MAX_N mutex (limit>1) — mutexLimit already filled by higher-priority rules |
GROUP_PRIORITY_LOST | EXCLUSIVE activation group (limit=1) — another rule won by priority |
GROUP_LIMIT_REACHED | MAX_N activation group (limit>1) — executionLimit already filled |
ACTION_ERROR | Action execution raised an error |
ENGINE_ERROR | Engine-internal error during evaluation |
reasonDetail is nullable — it carries a human-readable message when the engine has additional context to surface (e.g., the specific limit value that was hit).
See Decision Trace in the Policy Rules reference for the full status × reasonCode mapping.
Checking Requirements
Before running a Dry Run, check which facts the version expects:Dry Run Compare
Compare how two versions evaluate the same input facts, side by side:Next Steps
Impact Simulation
Test against hundreds of historical inputs at once.
Deployments
Deploy your validated version to production.

