Verifying Rule Sets
The Verify tab checks a rule set by reading it, not by running it. It finds rules that can never fire, rules that duplicate or shadow each other, rules that fight over the same context key, broken references, keys nothing supplies, and combinations of inputs no rule covers — before a single run happens.
Running a check
Open a rule set and choose the Verify tab. The first pass starts on its own; after that, press Re-analyze whenever you want a fresh answer. The check reads the copy of the rule set open in the editor, so it sees your unsaved edits — you do not have to save first to find out whether a change fixed a finding.
Nothing runs Verification is read-only. No actions execute, no AI calls are made or billed, nothing lands in run history or logs, and your monthly run count is untouched. Re-analyze as often as you like.
Reading the findings
The top of the panel counts what was found by severity, then lists each finding as a plain sentence. Where it makes sense, a finding also names the rule it is about, the context key involved, or the input region it describes.
| Severity | Means |
|---|---|
| Error | The rule set is broken or cannot do what it says — a missing reference, or a retractable rule that cannot honor its own promise. Fix these. |
| Warning | The rule set runs, but something in it has no effect or its outcome depends on rule order. Almost always worth a look. |
| Info | An observation. Often deliberate — a disabled rule, a gap you meant to leave, a scheduled rule that has not started yet. |
A clean rule set reports No issues found. Rules that are switched off or outside their active dates are reported once as such and then left out of the deeper checks — a rule that cannot run cannot duplicate, conflict with, or cover anything.
Rules that never fire, or fire and do nothing
| Finding | What it means |
|---|---|
| Empty rule set | The set has no rules, so running it can never match anything or produce output. |
| Rule disabled | The rule is switched off and is skipped on every run. |
| Rule expired, or not yet effective | The rule is outside its active window: past its expiration date and unable to fire again, or scheduled to start later and skipped until then. |
| Rule has no actions | The rule matches but changes nothing, so matching it has no effect. |
| Condition can never be true | The rule's own clauses contradict each other — no value can satisfy all of them at once. Where it can, the finding names the key that cannot be satisfied. |
| Unreachable because of the match limit | Enough rules above this one always match to use up Max rules to match, so evaluation stops before this rule is reached. |
| Only matches what an earlier rule already matches | Every input this rule fires on is already covered by an earlier rule that does the same thing, so it never changes the outcome. |
Rules that repeat each other
Two rules are compared by what they mean, not by how they are typed — the same test written two different ways is still recognized as the same test.
- Duplicate ruleWarning — same condition and the same actions. One of them can be deleted.
- Duplicate conditionInfo — same condition, different actions. Usually worth merging into one rule.
Rules that fight over a key
When two rules can both match the same input and both write the same context key, the finding says which one wins and why. Its severity follows how the rule set executes, because that is what decides whether the outcome is predictable at all:
| Rule set setting | Severity, and what the finding says |
|---|---|
| Randomize rule order on, or Rule sequence set to Parallel | Error — which value survives changes from run to run, or is not predictable at all. |
| Inference, with a different salience on each rule | Info — you have already said which rule should win, and the finding names it. |
| Anything else | Warning — the later rule silently overrides the earlier one. Under Inference with equal salience, the listed order breaks the tie. |
A related warning, order-dependent outcome, covers the case where both rules write the same key but at least one of the values is only known at run time. Nothing can be said about which value is right — only that whichever rule runs last decides it.
References and context keys
| Finding | What it means |
|---|---|
| Missing shared condition Error | The rule points at a shared condition that no longer exists, so it cannot be evaluated. |
| Missing action set Error | The rule points at an action set that no longer exists, so nothing runs when it matches. |
| Key nothing supplies Warning | A condition reads a key that is not a declared input, not a derived fact, and never written by an action. It will always be empty — usually a typo. |
| Key nothing reads Info | A rule writes a key that no condition, derived fact, action or tool output ever reads. Either something was meant to use it or the write can go. |
| Unused derived fact Info | A derived fact nothing reads. Facts are computed on demand, so one nothing asks for is never computed at all. |
| No fallback rule Info | Every rule has a condition, so an input that matches none of them produces no output. Add a rule with no condition if a default outcome is expected. |
Input combinations nothing covers
This is the completeness question a decision table invites. The check cuts each key your rules test into the distinct ranges they distinguish, then asks, for every combination of those ranges, whether some rule matches it. What nothing matches is reported in your own vocabulary rather than as a formula — “No rule matches when ‘tier’ is Gold and ‘amount’ is more than 100.”
Gaps are Info on purpose: plenty of rule sets deliberately handle only the inputs they care about. The first 20 regions are listed and the rest are counted, because a rule set with a systematic gap produces hundreds of them and the hundredth teaches nothing the second did not.
Gaps show up as the rows you are missing Switch to the Table view after a check and each uncovered region also appears there as a Not covered row, sitting under the columns it constrains, with a “N not covered” count in the toolbar above the grid. A coverage gap is a row that is not there, which no per-cell highlight can show.
Retractable rules
Rules that withdraw their conclusions automatically make a promise the engine has to be able to keep, so they get their own checks:
- Irreversible actionError — the rule withdraws its conclusions but has actions that cannot be undone. Withdrawing it would take back the context changes and leave those effects standing.
- Self-supporting ruleError — the rule reads a key it also writes, so it stops matching because of its own conclusion, and withdrawing that conclusion makes it match again.
- Support cycleWarning — retractable rules hold each other up in a loop. The run still finishes, but which conclusion survives depends on where the loop was cut.
- Support discarded by a plain ruleInfo — an ordinary rule writes a key a retractable rule is supporting, so if it fires the automatic retraction over that key is discarded and the value stays put. A legitimate way to pin a value, and an easy one to do by accident.
Goal-driven rule sets
A goal-driven rule set is searched backwards, by the context keys each rule writes. That makes two mistakes possible that no other mode has — a goal nothing can produce, and a rule the search cannot see — and both look the same from the outside: a run that fires nothing. These checks only apply when the match policy is Goal-driven.
- Goal nothing can establishError — no enabled rule writes the key, it is not a derived fact, and it is not a declared input, so every run reports it unproven. When the only rules that write it are switched off, the finding says so.
- Producer that cannot be readWarning — the rule writes keys that cannot be known without running it, so it is left out of the backwards search and a goal only it could establish will come back unproven. While such a rule exists, the “goal nothing can establish” check stands down for the whole rule set — that rule might be the thing that writes it.
- No goals at allWarning — nothing declared, and no decision keys or tool outputs to fall back on, so a run has nothing to work backwards from and fires nothing.
- Retractable rule that is never retractedInfo — the rule withdraws its conclusions automatically, but the rule set stops once its goals are resolved and only the forward cascade withdraws support. Turn on Then forward chain if the conclusion should be able to be taken back.
Whether the rule set can answer in one request
Synchronous execution returns the decision inside the caller's own request, which is only possible when nothing in the rule set pauses the run to wait for a separate one. Being slow is fine here — API and AI calls finish, and the run has a deadline. Being paused is not.
- Rule set cannot run synchronouslyError — the rule set is marked as synchronously executable, but a rule uses a human-intervention action, an extension callback, or an API action set to continue asynchronously. A caller would be left with no answer.
- Rule set could run synchronouslyInfo — nothing pauses a run, so the rule set can be exposed on the execute endpoint. Shown only while the setting is off, as a suggestion rather than a problem.
Both checks stand down when a rule runs another rule set, because that rule set's actions are not part of this analysis. The engine still refuses a pausing action if a run actually reaches one.
Checks that could not run
Some checks can only give an honest answer under conditions your rule set may not meet. Rather than guess, such a check stands down and says so: the panel shows a “N check(s) could not run” section you can expand, with a reason for each one.
Always read the skipped list. “No issues found” means the checks that ran found nothing — not that the ones that stood down would have.
Typical reasons a check stands down:
- A clause it cannot read through — a pattern match, an AI prompt, or a test for whether a value is present at all rather than a comparison it can divide into ranges.
- Randomized rule order, or a parallel rule sequence, when the check depends on a fixed order (the match-limit check).
- Too much to walk exhaustively: a condition with too many combinations, or rules spanning more keys or more regions than a coverage answer could usefully cover.
- A missing shared condition or action set, which leaves the set of keys the rule set writes incomplete — so the key checks cannot tell a typo from a key something supplies.
- An input form, or tool inputs that are not declared, supplying context keys — so a key that looks unsupplied may be perfectly fine.
- An action whose written keys cannot be known without running it.
Verification versus testing
The two answer different questions, and neither replaces the other.
| Verify | Test cases | |
|---|---|---|
| Question | Is anything in this rule set contradictory, redundant, or unreachable? | Does this input still produce the outcome I expect? |
| Needs | Nothing — it reads the rules as they stand. | Inputs and assertions you write. |
| Runs the rules | No. | Yes, in a sandbox. |
| Gates a release | No. | Optionally, with Require tests to pass. |
A good habit is to verify while you author — it catches the mistakes that are invisible in a passing test, like a rule that never fires or a second rule quietly overwriting the first — and to keep test cases for the behavior you never want to lose.
Verification reasons about the rule set as written. Once it is live, the environment's Analytics page answers the other half of the question: which rules never fire against your real traffic, whatever the rule set allows in theory.