Explain & Debugging
The Explain & Debugging APIs help you understand why a policy produced a specific decision.
This is one of the most important trust-building capabilities in the JavaScript SDK because it makes policy decisions transparent during development, testing, rollout, and production support.
The JavaScript SDK provides three real explain surfaces:
policy.explain()runtime.explain()runtime.explainCall()
Core Mental Model
Same decision path, but human-readable output
Explain APIs use the same compiled policy evaluation flow while surfacing:
- resolved action
- actor
- snapshot
- final effect
- matched rule
This makes them ideal for root-cause analysis.
policy.explain()
Use when you already have a full evaluation input.
policy.explain({
action: {
type: "refund",
amount: 5000,
},
actor: {
role: "finance",
},
snapshot: {
is_locked: false,
},
})
This evaluates the policy and prints structured output for:
- action
- actor
- snapshot
- result
It also returns the Decision object.
runtime.explain()
Use when debugging runtime decisions with resolvers.
runtime.explain({
type: "deploy",
environment: "production",
})
This automatically:
- resolves actor
- resolves snapshot
- evaluates policy
- returns decision
Best for:
- local debugging
- staging validation
- rollout safety
- live issue triage
runtime.explainCall()
The strongest debugging API for protected functions.
runtime.explainCall(refundOrder, {
args: ["order_123", 5000],
actionName: "refund",
})
This reconstructs the exact action payload using:
- object-first normalization
- explicit field mapping
- schema-driven mapping
Then it evaluates using the same runtime flow.
This is excellent for:
- API route debugging
- worker failures
- CI function tests
- agent tool tracing
- production support
Example Debugging Workflow
A common real-world flow:
const decision = runtime.explainCall(processRefund, {
args: ["order_123", 100000],
actionName: "refund",
})
console.log(decision.effect)
console.log(decision.matched_rule)
This helps answer:
- why was it blocked?
- why did approval trigger?
- which rule matched?
- did resolvers return expected context?
CI & Test Debugging
Explain APIs are ideal for failing CI tests.
try {
policy.assertEffect(input, "allow")
} catch {
policy.explain(input)
}
This makes regression failures easy to diagnose.
Production Rollout Safety
During staged rollout, combine explain with shadow mode.
const decision = runtime.explainCall(handler, {
args: requestArgs,
actionName: "deploy",
})
Use this for:
- new policies
- policy migrations
- governance changes
- incident debugging
Resolver Debugging
A major use case is validating resolver correctness.
Explain surfaces let you confirm:
- actor identity fields
- snapshot state
- missing resolver values
- incorrect field names
- stale business state
This is often the fastest way to debug policy mismatches.
Common Debugging Questions
Why was my function blocked?
Use:
runtime.explainCall(fn, ...)
Check:
effectmatched_rule- actor fields
- snapshot fields
Why didn’t approval trigger?
Check whether:
- action payload mapped correctly
- schema field names match
- snapshot state was present
- resolver returned expected values
Why didn’t any rule match?
Use explain output to inspect:
- action type
- missing fields
- incorrect role names
- wrong snapshot state
Best Practices
Use explainCall() for function issues
This gives the closest representation of production execution.
Use policy.explain() for tests
Best when full input fixtures are already available.
Use explain before rollout
Always validate:
- approval rules
- destructive actions
- production deploy gates
- tenant isolation rules
Production Mental Model
Incoming call
-> Build exact context
-> Explain decision
-> Inspect matched rule
-> Fix rule or resolver
This is the fastest way to build confidence in policy behavior.
Next Steps
- Add Observability & Audit
- Build Testing Policies
- Use Actor Resolvers
- Use Snapshot Resolvers