Skip to main content
Version: v0.16.4

Evidence Carrier Contract

The Evidence Carrier Contract defines a universal interface for carrying verifiable evidence across different transports. Instead of coupling receipt delivery to a single protocol, the contract provides a common type (PeacEvidenceCarrier) and adapter pattern (CarrierAdapter) that work across MCP, A2A, ACP, UCP, x402, and HTTP.


The problem​

Verifiable interaction records need to travel across many different protocols. An MCP tool response carries data differently from an A2A task status, which differs from an HTTP header. Without a common interface, every transport needs custom receipt handling logic, and evidence becomes non-portable.

The Evidence Carrier Contract solves this by defining one type that all transports can produce and consume.


PeacEvidenceCarrier​

The core type that represents portable evidence. Defined in @peac/kernel (Layer 0, zero runtime dependencies).

PeacEvidenceCarrier
interface PeacEvidenceCarrier {
receipt_ref: string; // sha256(receipt_jws) -- integrity anchor
receipt_jws: string; // Compact JWS (EdDSA, Ed25519)
receipt_url?: string; // Optional HTTPS-only locator hint (max 2048 chars)
policy_binding?: string; // Policy hash at issuance time
issued_at?: string; // ISO 8601 timestamp
carrier_version?: string; // Carrier format version
}

Key properties​

  • receipt_ref is always sha256(receipt_jws). Verifiers MUST check this integrity constraint at extraction time.
  • receipt_jws is the signed JWS artifact -- the actual receipt.
  • receipt_url is a locator hint only. It MUST NOT trigger implicit fetch (SSRF prevention). Callers who fetch the URL MUST verify sha256(fetched_jws) === receipt_ref.
  • policy_binding records which policy was in effect when the receipt was issued. Policy binding verification (JCS RFC 8785 + SHA-256, 3-state) is available in Interaction Record format.

CarrierAdapter pattern​

Each transport implements a CarrierAdapter<TInput, TOutput> with three operations:

CarrierAdapter
interface CarrierAdapter<TInput, TOutput> {
extract(input: TInput): PeacEvidenceCarrier | null;
attach(output: TOutput, carrier: PeacEvidenceCarrier): TOutput;
validateConstraints?(carrier: PeacEvidenceCarrier): boolean;
}
  • extract pulls a carrier from a protocol-specific container (e.g., MCP _meta, A2A metadata)
  • attach places a carrier into a protocol-specific container
  • validateConstraints checks transport-specific limits (e.g., 64 KB embed for MCP)

Transport implementations​

Each transport places evidence in a protocol-appropriate location:

TransportPlacementSize limitPackage
MCP_meta["org.peacprotocol/receipt_ref"] + _meta["org.peacprotocol/receipt_jws"]64 KB embed@peac/mappings-mcp
A2Ametadata[extensionURI].carriers[]64 KB embed@peac/mappings-a2a
ACPCustom headers8 KB header@peac/mappings-acp
UCPWebhook payload64 KB embed@peac/mappings-ucp
x402Response headers/body8 KB header@peac/adapter-x402
HTTPPEAC-Receipt header (compact JWS)8 KB header@peac/middleware-express
Transport-neutral evidence

The same receipt can be carried across any of these transports without modification. The carrier adapter handles placement and extraction; the receipt itself is identical regardless of transport.


Receipt reference integrity​

The receipt_ref field is the SHA-256 hash of receipt_jws. This is verified at extraction time:

Integrity check
import { computeReceiptRef } from '@peac/schema';

const carrier = extractMcpCarrier(toolResponse);
const expectedRef = await computeReceiptRef(carrier.receipt_jws);

if (carrier.receipt_ref !== expectedRef) {
throw new Error('Receipt reference integrity check failed');
}

This prevents tampering: if a transport modifies the JWS during delivery, the reference check will fail.


Discovery​

Agents and servers discover PEAC support through a 3-step process:

  1. Agent Card (A2A): check capabilities.extensions[] for https://www.peacprotocol.org/ext/traceability/v1
  2. Well-known: check /.well-known/peac-issuer.json for issuer configuration
  3. Header probe: check for PEAC-Receipt header in HTTP responses

Next steps​