Evidence records for AI agents

Verifiable evidence records for AI-agent swap decisions.

When an agent swaps and something goes wrong three weeks later, the question is: what did it know at signing time? Every keyed Routescore pre-sign check persists a durable evidence record — the full response verbatim, an identity-free actor context, and a SHA-256 content hash anyone can re-derive offline. Read-only decision support; Routescore never signs, executes, or moves funds.

Read the records guideAdd a pre-sign check to your agent
Inspect it yourself

Model a swap in the browser — keyed API calls of the same check persist a hash-verifiable evidence record.

Why agent swaps need an evidence trail

Agent execution tooling matured fast: an AI agent can plan a swap, build the transaction, and submit it without a human touching a keyboard. The evidence half moved slower. If a position sours later, an agent pipeline that kept no records cannot answer the only question that matters in the post-mortem: what was observed, modeled, and not evaluated at the moment of signing — and under which methodology version?

A preflight evidence record answers it with a document instead of a memory. Every keyed check_swap call persists a routescore.preflight_record.v0 record and returns three additive fields on the response: record_id (retrieve the record), evidence_bundle_id (the stored evidence bundle, minted with the response so the id is part of the hashed evidence), and record_output_hash (a SHA-256 content hash a third party can re-derive offline). Existing integrations keep working — the fields are additive and back-compatible.

  • record_id — fetch the full record via GET /api/public/v1/records/{record_id} or the get_preflight_record MCP tool.
  • evidence_bundle_id — names the stored evidence bundle; minted with the response, inside it, so it is part of the hashed content.
  • record_output_hash — a canonical-JSON SHA-256 hash of the record, re-derivable offline with no Routescore account.
  • Both evaluated answers persist: a 200 (clear / caution) and a 422 (unsupported) are both recorded; schema-invalid 400s never are.

What a record contains — and what it never contains

The record is a response-superset, never a fork: the full check response nests verbatim under its response field — no figure renamed, softened, or re-summarized. Around it the record adds only what an audit needs: an identity-redacted echo of the evaluated request, a declared actor type (human, agent, multisig, or unknown — declared by the caller, never verified, and anything else degrades to unknown rather than a guess), a reserved policy-reference slot, and the integrity block with the hash and its re-derivation recipe.

Two boundaries are structural. Records are identity-free by construction: they never store wallet addresses, ENS names, or emails — an actor label that looks like one is dropped before recording, not masked. And records are read-only evidence, never signing material: a response carrying calldata, transaction payloads, or signatures is rejected outright rather than stored, so a preflight record can never be replayed into an execution.

How a third party re-verifies the hash

The hash identifies the evidence content, not the storage row: record_id, recorded_at, and the integrity block itself are excluded, so re-recording identical evidence yields the identical hash. It is a content hash, not a signature — and it uses the same single recipe as every other Routescore artifact hash, so there is exactly one verification procedure to learn.

The recipe, stated inside every record: remove record_id, recorded_at, and integrity; serialize the remainder as canonical JSON — ECMAScript JSON.stringify applied to the recursively key-sorted value (arrays kept in order, no whitespace, ECMAScript number rendering and string escaping, no Unicode normalization); SHA-256 the UTF-8 string; prefix sha256:. If the result matches integrity.output_hash, the document is exactly what the check produced at decision time — and if any field were edited afterwards, the recomputed hash would no longer match. Non-JavaScript implementations must reproduce ECMAScript serialization semantics (number rendering is the usual divergence) or use the Node reference snippet in the records guide, which is normative. An auditor, a counterparty, or a future you can run it offline.

Owner-scoped retrieval, failure honesty, and outcome labels

Retrieval is keyed and owner-scoped: a key only ever sees records belonging to its own account, and a record id from another account is indistinguishable from a missing one — both return 404. GET /api/public/v1/records lists newest-first summaries with cursor pagination; GET /api/public/v1/records/{record_id} returns the pristine record document plus its stored evidence bundle; the get_preflight_record MCP tool gives an agent the same read.

Failure is stated, never papered over: if the durable write fails, the check response still returns in full — verdict and trust envelope unaffected — with the three linkage fields null plus a record_persistence_failed caveat, so a missing record is always visible as missing. And records never rewrite history: each summary carries an outcome_label_id that starts null and is set only after an after-the-fact outcome label reconciles the check with independently observed settlement data. Labeling never happens at decision time, and the original record is never edited.

FAQ

Common questions

What is a preflight evidence record?

The persisted form of a keyed check_swap response: a routescore.preflight_record.v0 document that nests the full response verbatim and adds an identity-free actor context, an identity-redacted request echo, and a SHA-256 canonical-JSON integrity hash. The response links to it via three additive fields — record_id, evidence_bundle_id, and record_output_hash.

How does a third party verify a record?

Offline, with no Routescore account: remove record_id, recorded_at, and integrity from the retrieved document, serialize the remainder as canonical JSON — ECMAScript JSON.stringify applied to the recursively key-sorted value (arrays kept in order, no whitespace, ECMAScript number rendering) — then SHA-256 the UTF-8 string, prefix sha256:, and compare with integrity.output_hash. Non-JavaScript verifiers must reproduce ECMAScript serialization semantics (numbers are the usual divergence) or use the normative Node snippet in the records guide. A match means the evidence is exactly what the check produced; any after-the-fact edit changes the recomputed hash.

Does a record prove the swap turned out well?

No. A record proves what the check showed at decision time — the verdict, caveats, gap states, and methodology version. Realized outcomes are a separate question, answered later by outcome labels built from independent settlement reconciliation, never by editing the record. Every figure inside the record stays modeled and point-in-time.

Who can read my records?

Only your account. The records endpoints are keyed and owner-scoped: a key only ever sees records created by its own account, and requesting another account’s record id returns the same 404 as a missing one. Records are also identity-free — they never contain wallet addresses, ENS names, or emails.

What happens if the record write fails?

The check response still returns in full — the verdict and trust envelope are unaffected — with record_id, evidence_bundle_id, and record_output_hash set to null plus a record_persistence_failed caveat. Nothing was persisted, and the response says so plainly instead of inventing an id.

Do I need an API key?

For records, yes: they are created by keyed check_swap calls, and the REST API plus the @routescore/mcp server are bundled with the Power tier. The browser route check at /route-check stays free and keyless — it models route quality without creating a record.

Run it yourself — no signup, no wallet.

Routescore is read-only, non-custodial decision support. Run a check, keep the record, review the outcome — modeled and point-in-time, not investment advice.

Read the records guide