Dispute verifiability: from he-said-she-said to provable

A dispute on the AIOUM network is settled on evidence, not on competing stories: when your agent says a call was paid for and never answered, the question is checkable, not argued. The canonical Merkle transcript format ships with cross-implementation pinned vectors (evidence-format.md); both node runtimes record durable transcripts and anchor the root on-chain before settling; ServiceRegistry carries the commitRequired service flag, snapshotted per session, so a flagged session cannot settle paid work without an anchored root, enforced in PaymentManager; @aioum/sdk sessions record their own transcript and voucher log and assemble evidence packages (session.evidencePackage(), session.verifyAnchoredRoot()); and the arbitrator-side verify-evidence CLI checks anchored roots, voucher authorization (EOA + ERC-1271), optional deterministic re-execution (--exec) and pluggable attestations.

Verifiability is a spectrum

raiseDispute(sessionId, evidenceURI) carries an off-chain evidence package, on IPFS for example, that an arbitrator inspects. How much of a ruling can be mechanical depends on the service class:

Service classExampleWhat can be proven
Deterministic computehash, transcode, query over pinned dataeverything — re-execute and compare
Attestable computemodel inference on fixed weightsTEE attestation / zkML (heavy)
Non-deterministic but boundedweb search, live-data feeddelivery + well-formedness, not "quality"
Subjective quality"is this LLM answer good?"essentially nothing — judgment forever

The goal is to move every dispute as far left as its service class allows and keep the subjective residue small, cheap and clearly labeled. Your agent may buy a hash one minute and an LLM answer the next; the first can be re-executed, the second only proven delivered and paid for, and the system is honest about which is which.

The anchor: commitResults

PaymentManager.commitResults(sessionId, resultsRoot) lets the operator commit a write-once hash over the calls it served, only while the session is Open, before settlement and before any dispute, so a faulty operator cannot rewrite history after a challenge; the commit doubles as the node's on-chain liveness ping. Every tier builds on this anchor, and the node runtimes commit it automatically before settling.

Tier 0: structured evidence on the anchor

The first tier needs no contract changes, only two conventions. On the node side, the results root is a Merkle root over per-call leaves:

leaf_i = keccak256(abi.encode(i, keccak256(request_i), keccak256(response_i), keccak256(toolId_i)))

The node keeps the raw transcript, the request and response bytes per call, in its VoucherStore-adjacent storage for the dispute window. On the client side, the evidence package that evidenceURI points to is a JSON document pinned to IPFS:

{
  "formatVersion": 1,
  "sessionId": "42",
  "chainId": 31337,
  "paymentManager": "0x..",
  "claim": "non-delivery | wrong-result | quality",
  "calls": [ { "index": 3, "toolId": "wordcount", "request": "...", "response": "..." } ],
  "vouchers": [ { "cumulativeAmount": "5000000", "signature": "0x.." } ],
  "resultsRoot": "0x..",
  "narrative": "free text for the subjective residue"
}

(calls is the full index-ordered transcript; the arbitrator recomputes the root from it and compares against the anchored sessionResultsRoot, so no per-call proof travels in the package.)

An arbitrator then checks mechanically that the vouchers are signed by the session client (payment happened), that the transcript recomputes to the on-chain sessionResultsRoot (the node committed to exactly these responses), or that the node committed nothing while vouchers show payment (delivery unproven). The judgment left over is only the quality of a proven response.

Tier 1: mandatory commitment where it's cheap

The node runtime commits the results root once per session, immediately before it settles: one transaction per session, priced in. ServiceRegistry carries a service-class flag, commitRequired, and for flagged services an operator with no committed root and client-signed vouchers in hand loses non-delivery disputes by default. Absence of evidence becomes evidence of absence, but only where the service class opted in; elsewhere commitment is optional and absence proves nothing. On your side, the SDK stores its own copy of requests, responses and vouchers per session and assembles the evidence package automatically, so your agent never has to remember to keep receipts.

Tier 2: objective wrong-result disputes for deterministic services

Service metadata declares determinism as a pinned docker image digest and entrypoint in the service's descriptor card (see evidence-format.md §6). An arbitrator, or anyone who can reproduce the environment, re-executes the disputed call with verify-evidence --exec and compares against the Merkle-proven committed response. The vote becomes a machine check.

Tier 3: attestations and proofs

Attestations ride in the same evidence package (type: tee-nitro, tee-sgx-dcap, zkml, …) and dispatch through the verifier registry in verify-evidence (VerifyHooks.attestationVerifiers). A TEE quote attesting "this image produced this output", or a zkML proof for a small model, is simply a better checker for the same committed root. An attestation with no registered verifier is reported UNVERIFIED, not trusted.

What stays judgment

Subjective quality is never provable. For "the LLM answer was bad", the system proves what was delivered and that it was paid for; the rest is human judgment, reserved for exactly that residue. Committed roots prove commitment, not correctness: a node can commit garbage, and Tier 2 re-execution and Tier 3 attestations turn the anchor into a correctness check for eligible classes. Storage is bounded: transcripts are retained through settleChallengeWindow, bounded by session, and pruned after finality, following the node's durable VoucherStore pattern.

All of it makes the record of a call more legible, to a juror and to anyone else who looks.

Next: Privacy — how the SDK, the node and a bonded relay make your agent's public spend uninformative.