Explain a policy decision with the rule that decided
How a DSAIL check names the assertion that failed and carries its source text, so a person can be told exactly which condition a document failed and on which values, and why there is no combined verdict.
A result nobody can explain is a result nobody will act on. When a document fails a policy check, the next question is always which rule, and why. DSAIL answers it structurally: every result names the rule that decided, and carries that rule's source text.
What comes back
A check returns every rule in the ruleset, each with the assertions it states, each with the engine's own result:
{"rules": [
{"rule": "receipt_over_75", "assertions": [
{"name": "receipt_over_75", "check": "FALSE", "unknown_policy": "neutral",
"source": "assert receipt_over_75 { Implies(amount > 75 \"USD\", has_receipt) }"}]},
{"rule": "within_cap", "assertions": [
{"name": "within_cap", "check": "TRUE", "unknown_policy": "neutral",
"source": "assert within_cap { amount <= 5000 \"USD\" }"}]}]}
The explanation is the assertion's own text beside the values you submitted. Here receipt_over_75 requires a receipt once the amount is over 75 USD, and the claim dictionary said the amount was 120 and there was no receipt. A person reads the condition, reads the two values it depends on, and knows which fact to check. Nothing in that is a message the service composed, so it cannot drift from the rule that actually ran. Each rule holds a list of assertions, so a rule that one day states several is read the same way.
The response does not repeat your claim values back to you as an explanation. You already hold them, and the claims.bound and claims.unbound lists say which ones the engine had a value for.
Why there is no overall verdict
The service publishes no compliant/non-compliant, no severity and no ranking, on purpose. Choosing which of two violated assertions "really" describes a document requires knowing what each rule costs the business, and the service does not know that. What it knows — exactly what each assertion concluded — it reports in full, and the system reading the results folds them with its own knowledge. A model relaying the results is told to use the four words and attribute them to the rules: *the rules concluded that receipt_over_75 is FALSE*.
The four results
| Result | Meaning |
|---|---|
TRUE | The assertion holds over the submitted values. |
FALSE | It is violated over the submitted values. |
UNKNOWN | A claim it needs was submitted as unknown, or is unconstrained. Unknown is an answer, not a guess. |
AMBIGUOUS | Reserved: its evidence contradicted itself, which needs several answers for one claim. A claim dictionary holds one value per claim, so no check sent to this service returns it. Handle it; nothing you submit triggers it. |
Accounting for the values judged
When a numeric claim arrives in one unit and the rule compares in another, the response's claims.quantities block records the submitted value, the value bound, the unit it was measured in and the conversion the engine applied — with by: "engine" stating that nothing outside the solver touched the number. The factor shown is a description for a person to verify, never an input to the arithmetic, which runs in exact rationals.
Reproducing the explanation later
The response names ruleset_hash and unit_library_hash. Re-run the same claim dictionary against that pair and the bytes are identical — the same answer every time. An approval recorded against the hash says which person signed off on exactly those rules.
Try it
- Quickstart: REST — the full check response, in three calls.
- Enforce a policy and get the same answer every time — why the seam is the claim dictionary.