Skip to main content

Verified Decisions API

The flagship neuro-symbolic-recursive surface. Instead of generating free text, it returns an auditable decisionapproved | denied | refused — with a cited proof chain, a confidence, and a safe refusal when the engine cannot ground the answer well enough to be accountable. This is the use case where a pure LLM is unsafe: it will confidently approve actions that violate policy. The symbolic layer gives deterministic, provenance-traced decisions relative to the supplied facts and rules; the recursive layer handles multi-hop policy (transitive role access, bill-of-materials/recall explosion, chained eligibility); the neural layer reads messy natural-language requests. Every request also runs through the canonical Grounded Symbol System (GSS) and a tenant-scoped NSRMachine. Machine inference is mandatory for verified decisions — if the seed pack is unavailable or inference does not complete, the API fails closed with HTTP 503.
This page reflects NSR v0.7.0. Several rule-evaluation semantics were corrected in v0.6.0 and v0.7.0 — see Behavior changes. If you wrote rules against earlier docs, read that section.

Endpoints

Request

Rule effects

A rule may declare its policy intent explicitly via effect, which is authoritative over predicate-name conventions — better for tenant-specific or non-English vocabularies.
effect: "review" became a first-class declared effect in v0.6.0. Before that it was expressible only via predicate-name inference, and an inline rule declaring it would fail with a 422 “unknown variant”. Review rules are subject-bound in the same way deny rules are.

Negation-as-failure

A condition may set negated: true: the rule fires only when no fact matches the atom. A free variable in the negated atom is a wildcard, so not fraud_flagged(?o, ?r) fails whenever any fraud_flagged(?o, *) exists.
This field is required for negation to take effect. Before v0.6.0, request-scoped rule conditions carried no negated flag, so a negation was silently dropped and read as a positive condition — inverting the guard. A rule written as may_auto_refund(?o) :- refund_requested(?o), NOT fraud_flagged(?o,?r) would auto-refund exactly the fraud-flagged orders it was written to block.Organization rules on the batch endpoint always honored negation; inline rules — what the MCP nsr_decide tool uses — did not. If you authored inline rules against pre-v0.6.0 docs, audit them.
negated is serde-default and skipped when false, so existing payloads are unchanged.

Outcomes

Cited symbolic policy is evaluated after GSS safety gates but before conversational uncertainty and execution-runtime state. This matters when policy authorizes an action but answer composition is ambiguous or live runtime state disagrees.

Response

cited_rules is the audit trail, reduced to the backward dependency path. When the request carried inline policy, the proof also carries a SHA-256 over the canonicalized request-scoped facts and rules, pinning the decision to the exact policy inputs it was evaluated against.

Behavior changes in v0.6.0 and v0.7.0

Several of these were fail-open correctness bugs. If you built against earlier documentation, the following now behave differently — in every case, more conservatively.

Confidence is capped by the weakest supporting fact (v0.7.0)

Decision confidence was 1.0 - grounding_uncertainty, decoupled from the proof and non-monotonic — a 0.4-confidence fact could yield higher confidence than a 1.0 one. An approval is now capped by its weakest supporting fact:
This is fail-safe (it only lowers values), monotonic, and a no-op when facts are certain.

Subject and action binding (v0.6.0)

A rule fires for whatever the fact base satisfies, not for what the question asks. Given may_authorize(?p,?act) :- has_authority(?p,?act) and the fact has_authority(ceo_kim, approve_wire), the engine proves may_authorize(ceo_kim, …). The gate previously counted any cited request-scoped effect wholesale, so a wire could be authorized for stranger_sven off the CEO’s authority, or delete_account authorized off refund authority. A single conclusion-head check now covers all effects: the cited rule’s effect only applies when its ground conclusion binds the request’s own subject and action. Two related binding fixes:
  • Numeric builtins — the binding gate replays a cited rule’s body to reconstruct which subject it fired for, but the replay matcher did not evaluate comparison builtins (leq, geq, lt, …). It returned “can’t tell”, so no mismatch was detected. A rule may_refund(?o) :- order_amount(?o,?v), leq(?v, 500) could approve a refund for an order whose amount did not qualify. The matcher now computes comparison builtins under the binding, exactly as the solver does.
  • Single-character subject tokens — the subject-binding token match dropped tokens shorter than 2 characters, so ord-9 and ord-4 (sharing ord, differing only in the 1-char suffix) were treated as the same subject. A rule that fired for ord-9 could bind a decision about ord-4. The match now requires every alphanumeric token, single characters included. Phrasing variance (order A1 vs order #A1) still grounds.

Abduction no longer asks for un-suppliable builtins (v0.7.0)

A failed comparison builtin such as leq(850,500) was reported in missing_facts with a resolves_with, telling an agent to “supply leq(850,500)” — impossible. Comparison builtins are now excluded; the actionable ask is the base predicate that binds the value, e.g. amount.

MCP server

The NSR MCP server gained a per-request timeout (NSR_TIMEOUT_MS) so an agent never hangs on a slow endpoint, plus client-side input validation that names the exact malformed rule or field instead of surfacing a cryptic 422 deserialize error.

Verification

NSR ships a verifier-as-oracle evaluation apparatus: a 1,260-case auto-labeled decision-soundness corpus, a deterministic generator, and a runner that checks any live /v1/decisions deployment against the ground-truth labels — plus in-process property-based and generative multi-invariant soundness tests.