Docs · Deterministic mode

For claims that are lookups,
not judgments.

POST /v1/verify-facts resolves a claim with a deterministic check and signs the result. No LLM is invoked anywhere in the pipeline. The receipt records check_mode: "deterministic" so a verifier can prove that — not take our word for it.

Why this exists

The reasonable objection to any verification service is: who checks the checker? If an LLM decides whether a claim is true, the trust chain contains a model, and the model is the weakest link in an audit.

Some claims do not need judgment. "Does this signature verify against this key" is not an opinion. "Does this package exist in PyPI at this version" is a lookup. "Is this timestamp inside this window" is arithmetic. For that class, the honest answer is to run the check and sign the result — with nothing probabilistic in the path.

What the mode claims: no LLM in the trust chain, recomputable end-to-end, same envelope and same verifier as every other AgentOracle receipt.

What it does not claim: that the underlying source is correct. A deterministic check proves what was checked and what the check returned — not that a registry, a key, or a schema is itself trustworthy. It also does not make the caller's agent AI-free; the agent may well have used a model to generate the claim. The guarantee is scoped to our check.

Shipped check types

This list is not written into the page. It is fetched from GET /v1/verify-facts when you load it — the same endpoint that serves the checks. If the catalog and this page ever disagree, the catalog is right and this page is broken.

Live catalog pulled from GET /v1/verify-facts
loading catalog…
Check typeResolvesRequired input
signature_verification Does this signature verify against this key? Ed25519 / EdDSA. signing_input_b64u, signature_b64u, public_jwk
hash_comparison Does the claimed digest match a digest computed over the content? SHA-256 / SHA-512, timing-safe compare. claimed_digest, and content or content_b64u
registry_lookup Does this entry exist in a declared authoritative registry, with matching metadata? Allowlisted registries only. registry, identifier, optional expect
regex_match Does this value match a declared pattern? value, pattern, optional flags
timestamp_validation Does this timestamp fall inside declared bounds? timestamp, and not_before and/or not_after
json_schema_conformance Does this document conform to a declared schema? Documented keyword subset; unsupported keywords are rejected, never skipped. document, schema

Call shape

$ curl -sS https://agentoracle.co/v1/verify-facts \
    -H "authorization: Bearer $AO_API_KEY" \
    -H "content-type: application/json" \
    -d '{
      "subject": { "claim_hash": "sha256-…" },
      "checks": [
        {
          "check_type": "hash_comparison",
          "input": {
            "content": "the exact bytes being attested",
            "claimed_digest": "sha256-…"
          }
        },
        {
          "check_type": "registry_lookup",
          "input": {
            "registry": "pypi",
            "identifier": "agentoracle-receipt-verify"
          }
        }
      ]
    }'

What comes back

{
  "jws": { "payload": "…", "signatures": [ … ] },
  "canonical_sha256": "sha256-…",
  "verdict": "act",
  "check_mode": "deterministic",
  "check_types_applied": ["hash_comparison", "registry_lookup"],
  "check_results": [ { "check_type": …, "outcome": "pass", "evidence": { … } } ]
}

Inside the signed payload, check_mode: "deterministic" and check_types_applied[] sit under the signature, so they cannot be added or removed after issue without breaking verification. v_gate.confidence is 1.0 by construction and v_gate.v_adversarial_result is "n/a" — there is no judgment to contest and no probability to report.

Rejection: 422 claim_not_deterministic

If a claim cannot be resolved by a shipped check type, the endpoint refuses it. There is no fallback to the judgment path. A silent escalation to /v1/compose would mean a caller who asked for a deterministic receipt could receive a model-judged one without knowing — which would make check_mode worthless as a signal.

HTTP/1.1 422 Unprocessable Entity

{
  "error": "claim_not_deterministic",
  "reason": "Claim cannot be resolved by any deterministic check type…",
  "supported_check_types": [ … ],
  "llm_fallback": false
}

Two rejection cases, deliberately distinguished

Move to POST /v1/compose or POST /evaluate if you want judgment. That has to be an explicit decision by the caller.

Design constraints worth knowing

Registries are allowlisted, not freeform

A caller cannot pass an arbitrary URL. Beyond the obvious request-forgery surface, an open fetch would destroy recomputability: a caller could point the check at a server they control and obtain a signed receipt attesting whatever that server returned. Each lookup pins a response_sha256 and observed_at in the evidence, so the receipt stays auditable after the upstream registry changes.

Unsupported schema keywords are rejected, not ignored

json_schema_conformance ships a documented subset. A schema using keywords outside it returns 422 rather than validating against the part we understand. Silently skipping unknown keywords would issue a signed receipt attesting a check that was never performed.

One canonicalization implementation

Deterministic-mode receipts are canonicalized and signed by the same RFC 8785 JCS implementation and the same Ed25519 key as every other AgentOracle receipt. There is exactly one canonicalizer in the process — a second copy would silently diverge from the reference verifiers in the conformance suite.

Verifying a deterministic receipt

Nothing changes on the verifier side. Same envelope, same published JWKS, same reference verifier.

$ pip install agentoracle-receipt-verify
$ python3 -c "import json,sys; from agentoracle_receipt_verify import verify; print(verify(json.load(open('receipt.json'))))"
✓ valid: True — signature verifies against published JWKS (offline)

To confirm the mode independently, decode the payload and read check_mode yourself. It is inside the signed bytes; if it says deterministic and the signature verifies, no model was in the trust chain for that decision.

Conformance vectors for each check type — including the rejection cases, which must never produce a receipt — ship in the receipt-spec repo so a second implementer can byte-match the deterministic path the same way the judgment path is already matched.

Availability

Deterministic mode is a capability of the existing tiers, not a separate product. Self-Serve keys and x402 pay-per-call both reach POST /v1/verify-facts with no change to your credentials. Verification is free and offline, as it is for every AgentOracle receipt. See pricing.