Validate a claim

    An agent can cite a real article and still misquote it, or declare a conclusion settled when it rests on a fact only you can confirm. validate_claim catches both before the conclusion reaches your report. Your agent hands the gateway its reasoning as a graph: the provisions it cites, the quotes it took from them, the facts you told it, the assumptions it recorded, and the conclusions it draws. The gateway refetches every cited provision under your own access, compares each quote with the served text, and reports the strength each conclusion can carry. It never answers "passed".

    The check reads only what the graph declares. A fact or assumption the agent leaves out of the graph is invisible to it, so the value of the tool depends on the agent naming its inputs honestly.

    The claim graph

    The graph is a JSON object with a schema (ansvar.claim-graph.v2; v1 is still accepted but has no evidence nodes), the question being answered, the variables the reasoning turns on, any gaps the agent knows it left, and a list of nodes. Every node has an id and a kind:

    • clause — a provision the reasoning rests on: canonical_ref, the quote the agent took, its quote_language, the binding it reads (mandate, prohibition, permission, designation or definition), and a lookup address. In v2 the address is exact: lookup.source_id is the served row's citation.source_id and lookup.canonical_ref must equal the node's canonical_ref; law and article overrides are refused. Add jurisdiction when the source is registered under more than one jurisdiction code.
    • evidence (v2 only) — a served row that is not a statutory provision: a regulatory update (source_id: reg-intel), a CVE (cve-intel), a decision. Carries the routed source_id, the exact reference it was served under, an optional quotation, and jurisdiction under the same rule as clauses.
    • fact — a statement you gave the agent about your organisation, provenance: customer.
    • assumption — a statement the agent assumed, provenance: assumed.
    • interpretation and conclusion — a statement, a typing of DET (the text settles it) or INT (a reading), and depends_on, the ids of the nodes it rests on.

    A minimal graph, one provision and one customer fact:

    {
      "schema": "ansvar.claim-graph.v2",
      "question": "Must we report a major ICT incident to our competent authority?",
      "variables": {},
      "gaps": [],
      "nodes": [
        {
          "id": "C1", "kind": "clause",
          "canonical_ref": "DORA:art_19",
          "lookup": { "source_id": "eu-regulations", "canonical_ref": "DORA:art_19" },
          "quote": "Financial entities shall report major ICT-related incidents to the relevant competent authority as referred to in Article 46 in accordance with paragraph 4 of this Article.",
          "quote_language": "en",
          "binding": "mandate"
        },
        { "id": "F1", "kind": "fact", "statement": "We are a licensed credit institution in Germany.", "provenance": "customer" },
        {
          "id": "K1", "kind": "conclusion", "typing": "DET",
          "statement": "We must report major ICT-related incidents to BaFin.",
          "depends_on": ["C1", "F1"]
        }
      ]
    }

    The graph argument is that object serialised as a JSON string, not the object itself; an object is refused before any refetch. Send the prose answer alongside it as answer and the gateway compares its quotations too; leave it out and the response lists that check under not_checked.

    What the gateway checks

    1. Refetch. Every clause and evidence node is fetched again under your tier and add-ons. A source your access does not cover comes back withheld, never as content; a reference the corpus does not serve comes back not_served; a transport failure or timeout comes back unavailable. Nothing is taken from the graph on trust.
    2. Bind. The clause quote is compared with the served text. A match marks the clause bound; a quote that stops short of the served sentence without marking the omission binds with an unmarked-omitted-tail warning (an omission elsewhere in the quote is not detected). A quote in a different language from the served text counts as a reading at best; a row served without language metadata stays unverified rather than assumed to match. Evidence nodes resolve separately: a resolved row reports resolved_evidence with a resolution verdict, but resolution is not claim support, so the node stays UNVERIFIED and so does every conclusion that depends on it.
    3. Propagate. Strength flows through depends_on and a node carries the weakest strength among its inputs. DET needs bound text in the declared language with nothing capping it. INT is the ceiling for a declared reading, a translation, a bound clause whose edition the corpus tracks but has not verified, and every fact and assumption, which the gateway records as unconfirmed rather than adjudicates. UNVERIFIED is anything that could not be checked, plus a node in a dependency cycle or a derived node that reaches no clause at all. Every fact or assumption a node rests on is listed under its conditional_on.
    4. Report. A summary block states, in plain words, what each conclusion rests on and lists every finding and every limit; the typed result underneath lists every check it ran (checked) and did not run (not_checked) with a reason for each.

    Reading the response

    The response opens with a summary block written by the gateway, not by the agent: a headline, one entry per conclusion, an attention list, the limits, and a display_markdown text the agent is asked to relay unchanged. It describes what was matched and what each conclusion rests on. It never says a claim holds. For a four-conclusion graph (one provision matched, one withheld, one regulatory update resolved, one customer fact, one wrong paragraph pinpoint) the relay text reads:

    **Claim check** — 4 conclusions checked; 2 declared settled by the provision came back weaker. Not a verdict: what was matched and what each conclusion rests on.
    
    **K1** "We must report major ICT-related incidents to BaFin." — rests on your input (declared settled, came back weaker).
      Because: F1 — your input, not checked by the gateway: "We are a licensed credit institution in Germany."
      Matched provisions: DORA:art_19 (EU, served in en).
      Next: Confirm the input, or state the conclusion as conditional on it.
    
    **K2** "BaFin's guidance sets the reporting template." — rests on resolved evidence; claim support not assessed.
      Because: E1 (reg-intel REG-2026-0912) — reference resolved, quotation matched; claim support not assessed
      Next: Treat the conclusion as sourced, not checked: level 1 does not assess whether evidence supports a claim.
    
    **K3** "Financial entities must report major ICT incidents." — quotations matched; reasoning not checked.
      Matched provisions: DORA:art_19 (EU, served in en).
      Next: The quoted provisions are real and match; whether they support this conclusion is your judgment.
    
    **K4** "BaFin is the competent authority." — support not established by this check (declared settled, came back weaker).
      Because: C2 (DORA:art_46) — source withheld. Read the withheld reason (licensing, edition, scope or plan) before citing this source.
      Next: Resolve the source problem the reason names, then run the check again.
    
    Attention: error: paragraph_pinpoint C1 — pinpoint '(2)' differs from located ['1'] | error: G5 C2 — withheld | some sources were withheld under your plan or licence
    
    Not checked here: whether a provision is in force today; whether the reasoning translates the provision correctly; whether these rows were served to you in an earlier call; whether the conclusion follows from its premises (logic and entailment); quotations in a prose answer (no answer supplied).

    Each conclusion gets one outcome, chosen by what you must do first: support not established by this check (a cited item failed: withheld, not served, not reached, quotation not found), rests on resolved evidence; claim support not assessed (a regulatory update, CVE or decision resolved, but level 1 does not judge whether it supports the claim), rests on an assumption, rests on your input, a reading of matched provisions (a translation, an unverified edition, or a conclusion the agent itself declared a reading), or quotations matched; reasoning not checked. "Declared settled, came back weaker" is added whenever a conclusion the agent declared settled computed lower. The attention list carries every error and warning the check produced, whether or not it changed a conclusion's strength, so a wrong pinpoint or an unmatched quotation in a prose answer is never hidden by a strong conclusion.

    For integrators: the machine layer

    Below the summary the response keeps the typed result the summary is derived from. nodes carries each node's status (bound, withheld, not_served, unavailable, resolved_evidence, unconfirmed, analysed, and the quotation-mismatch states), its strength (DET, INT, UNVERIFIED), reasons and conditional_on. conclusions adds declared and a reason_chain per dependency. findings lists structural and quotation problems by check id; the G6 error is the overclaim the summary renders as "came back weaker". checked and not_checked list every check by id with a reason. Strength ranks UNVERIFIED below INT below DET and a node carries the weakest strength among its inputs; facts and assumptions are INT and unconfirmed; UNVERIFIED means the check could not establish support for that node, never that the claim is false. bounded and unreached_clauses sit at the top level (see Limits).

    Limits

    • At most 100 nodes and 60 refetches (clause and evidence nodes together) per graph; 128 KiB of graph JSON and 64 KiB of answer prose. Larger inputs are refused before any refetch, with the offending field named.
    • The refetch phase has a 25-second budget. A large graph citing one corpus takes tens of seconds. When the budget runs out the response is marked bounded: true, states how many clause and evidence refetches it did not finish in unreached_clauses, and leaves those nodes and the conclusions that depend on them UNVERIFIED. Finished nodes keep their real status.
    • Pan-European preparatory works are not resolvable through this tool yet and refuse explicitly.

    What it does not do

    Read the output as evidence for your review, not as a verdict. The check does not prove that a row was served to you in an earlier call; it proves the row is served now. It does not judge whether the reasoning translates the law correctly, since a wrong reading can bind to real text. It does not verify that a provision is in force today. It does not evaluate the logical constraints or entailments a graph may carry; they are validated and kept, not solved. And it does not confirm your facts: a conclusion conditional on a customer fact can be no stronger than that fact, and may be weaker for other reasons.

    Asking for it

    The tool is available on every tier. The useful moment is after the agent has fetched the statute text and before it states a conclusion:

    Using Ansvar: build a claim graph for that conclusion and run validate_claim on it before you state it. Show me every conclusion whose strength came back lower than declared, and what it is conditional on.