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, and a list of nodes. Two keys are optional: the variables the reasoning turns on and any gaps the agent knows it left. Every node has an id and a kind:
- clause — a provision the reasoning rests on:
canonical_ref, thequotethe agent took, itsquote_language, thebindingit reads (mandate, prohibition, permission, designation or definition), and alookupaddress. In v2 the address is exact:lookup.source_idis the served row'scitation.source_idandlookup.canonical_refmust equal the node'scanonical_ref;lawandarticleoverrides are refused. Addjurisdictionwhen 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 routedsource_id, the exactreferenceit was served under, an optionalquotation, andjurisdictionunder the same rule as clauses. - fact — a
statementyou gave the agent about your organisation,provenance: customer. - assumption — a
statementthe agent assumed,provenance: assumed. - interpretation and conclusion — a
statement, atypingofDET(the text settles it) orINT(a reading), anddepends_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?",
"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"]
}
]
}Pass that object as the graph argument as it stands. A JSON-encoded string of the same object is still accepted. 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
- 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 backnot_served; a transport failure or timeout comes backunavailable. Nothing is taken from the graph on trust. - 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 reportsresolved_evidencewith a resolution verdict, but resolution is not claim support, so the node staysUNVERIFIEDand so does every conclusion that depends on it. - Propagate. Strength flows through
depends_onand a node carries the weakest strength among its inputs.DETneeds bound text in the declared language with nothing capping it.INTis 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 asunconfirmedrather than adjudicates.UNVERIFIEDis 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 itsconditional_on. - Report. A
summaryblock states, in plain words, what each conclusion rests on, the errors and warnings that need attention, 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. A matched quotation does not show that a conclusion is supported; claim support was not checked.
**K1** "We must report major ICT-related incidents to BaFin." — rests on your input (declared settled, came back weaker).
Claim support: not checked; agent declared: settled by the provision.
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.
Claim support: not checked; agent declared: a reading.
Because: E1 (reg-intel REG-2026-0912) — reference resolved, quotation matched; claim support not assessed. Level 1 does not assess whether evidence supports a claim.
Matched provisions: DORA:art_19 (EU, served in en).
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; whether they support the conclusion was not checked.
Claim support: not checked; agent declared: settled by the provision.
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).
Claim support: not checked; agent declared: settled by the provision.
Because: C2 (DORA:art_46) — source withheld: edition_held; The requested edition is 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 the cited evidence supports each conclusion (claim support); 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); whether the declared gaps are answerable from the served corpus; 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; whether they support the conclusion was not checked. "Declared settled, came back weaker" is added whenever a conclusion the agent declared settled computed lower. The machine findings list keeps every finding. The summary shows errors and warnings in three places: the attention list, the "came back weaker" flag for an overclaimed conclusion, and a Because note on a conclusion whose stated quantity is not in the cited text. Informational findings stay in the machine layer. A wrong pinpoint or an unmatched quotation in a prose answer is never hidden by a strong conclusion.
The response keeps what the gateway checked apart from what your agent judged. On every node, evidence_checks records the checks themselves: whether the source resolved, whether the quotation matched, the served language, and the dependencies. On interpretations and conclusions, agent_assessment holds declared_typing (the DET or INT the agent declared) and attribution: "agent_judgment". evidence_ceiling is the highest typing the checked evidence allows, and claim_support is always not_checked. A matched quotation shows the text is real and quoted correctly; it does not show that the text supports the conclusion. That part stays your review.
One evidence check looks at numbers. On interpretations and conclusions, evidence_checks.stated_quantities says whether each plain deadline, duration, percentage or euro amount in the statement appears in the cited text: all_in_cited_text, not_in_cited_text, not_checked (including any text not declared English; the check reads English only) or not_applicable (no plain quantity). With not_in_cited_text, stated_quantities_detail gives missing, cited, cited_from and suggested_correction, and the findings carry a quantity_consistency warning. For a conclusion, the summary adds a Because note asking where the value comes from. For an interpretation, the warning appears in the attention list, and dependent nodes receive a reason naming the interpretation. This is a fact about the text, not a finding that the conclusion is false: "36 hours" can be derived from "half of 72 hours". It changes neither the evidence ceiling nor the outcome.
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 evidence_ceiling (DET, INT, UNVERIFIED; the legacy field strength carries the same value), evidence_checks, agent_assessment, claim_support, reasons and conditional_on. The summary's conclusions carry evidence_ceiling, declared_by_agent and claim_support, and, since summary schema ansvar.claim-check.summary.v2, the stable codes outcome_code (not_established, evidence, assumption, fact, reading, matched) and declared_code (DET, INT). Match on the codes; the outcome and declared phrases are display text; conclusions in the typed result 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 checked evidence or dependencies did not permit a verified evidence ceiling, never that the claim is false. Whether the claim is supported stays not_checked at every ceiling. 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 inunreached_clauses, and leaves those nodes and the conclusions that depend on themUNVERIFIED. 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.