Auditing Rules

Track which rules fired, skipped, stopped, or failed - or preview it with dryRun().

On this page

Auditing Rules

Rule auditing tells you which rules fired and which didn't. A RuleBook tracks this in a RuleStatusMap. Give your rules a name so the audit trail is meaningful - otherwise you'll see the rule's internal UUID instead. You can name a rule in any of these ways:

// Using the Builder
builder.rule( "ruleName" )

// Using newRule()
addRule( newRule( "ruleName" ) )

// Or its setter
addRule( newRule().setName( "ruleName" ) )

Rule states

Each rule added to a RuleBook has its state tracked via RULE_STATES, exposed on every RuleBook instance:

StateMeaning
REGISTEREDThe rule has been added to the RuleBook, not yet evaluated this run
EXECUTEDThe rule's when() (and except()) passed and its then() action(s) completed successfully
SKIPPEDThe rule's when()/except() condition did not pass
STOPPEDThe rule executed and then called stop(), halting the chain
FAILEDA then() consumer threw - see Error Handling
NOT_AVAILABLEReturned by getRuleStatus() for a name that isn't in the map

RuleBook.run() resets every registered rule's status back to REGISTERED at the start of each run, so a rule that a shorter chain doesn't reach this time around never reports a stale status left over from a previous run.

Reading the audit trail

status = ruleBook.getRuleStatus( "rule1" )
status = ruleBook.getRuleStatus( "rule2" )

Or retrieve the entire map:

writeDump( ruleBook.getRuleStatusMap() )

Dry-run / explain mode

Sometimes you want to know which rules a given set of facts would trigger, without actually triggering them - no then() consumers run, no facts are merged into the sticky fact store, no Result is touched, and the real audit trail (getRuleStatusMap()) is left exactly as it was. dryRun() gives you that preview, on both RuleBook and Rule:

report = ruleBook.dryRun( { "creditScore" : 550 } )
writeDump( report )

RuleBook.dryRun() returns an array of structs, one per rule reached, in execution order:

[
	{ "name" : "checkBlocklist",         "wouldExecute" : false, "wouldStop" : false },
	{ "name" : "creditScoreAdjustment",  "wouldExecute" : true,  "wouldStop" : false }
]

The walk stops exactly where a real run() would stop - the first rule whose condition passes and has stop() set. Rules after that point are never reached, so (just like a real run) they simply don't appear in the report.

A single Rule can also be dry-run on its own - and unlike run(), it doesn't require being attached to a RuleBook first:

report = newRule()
	.when( ( facts ) => facts.creditScore < 600 )
	.stop()
	.dryRun( { "creditScore" : 550 } )

// { "name" : "...", "wouldExecute" : true, "wouldStop" : true }
Edit this page Download Markdown Last updated Sep 17, 2026, 7:29:54 PM