Explain mode
Explain mode traces every condition in every rule, showing which checks matched, which didn't, and what values were resolved. Great for debugging and audit trails.
Enabling explain mode
CLI:
cc evaluate --policy ./policies --input ./input.json --explain
Go API:
eng := evaluator.NewFromPolicies(policies,
evaluator.WithExplain(true),
)
results := eng.Evaluate(doc)
fmt.Print(evaluator.FormatExplain(results))
Trace output
Each condition is annotated with + (matched), - (did not match), and the actual value resolved from the document.
RULE "blast-radius" [forbid] -> DENIED
+ condition: count(plan.destroys) > 5 -> true (got 8)
- unless: author.teams contains "platform-team" -> false (got [dev, backend])
-> too many destroys (8) — requires platform-team
RULE "sensitive-resources" [forbid] -> PASSED
+ condition: resource.type in ["aws_iam_role", ...] -> true (got "aws_iam_role")
+ unless: author.teams contains "enterprise-security" -> true (got [enterprise-security, dev])
-> saved by unless clause
RULE "no-draft-production" [forbid] -> PASSED
+ condition: pr.draft == true -> true (got true)
- condition: project.workspace == "production" -> false (got "staging")
-> conditions not met, rule did not fire
Complete traces
In explain mode, the evaluator continues evaluating all conditions and unless clauses even after a mismatch, so the trace is always complete. This is slower than normal evaluation but gives you the full picture for debugging.
Use cases
- Debugging a confusing rule result — see exactly which condition failed and what value it saw.
- Audit trails — log per-condition traces as structured output for compliance.
- Dry-run review — explain mode on a set of sample inputs is an effective way to validate a new policy before enforcing it.