Conformance
Three independent implementations of the Agent Receipt Protocol — the Go, Python, and TypeScript SDKs — verify one another’s receipts. Every conformance vector is signed once with a single shared Ed25519 keypair; each SDK then re-verifies the signatures, canonical JSON (RFC 8785), and receipt hashes the other two produced. Verification is exercised in both directions: a positive corpus every implementation must accept, and a MUST-reject corpus of tampered receipts and broken chains every implementation must refuse. The frozen vectors span four pinned spec versions (v0.2.0 through v0.5.0), so a receipt emitted by any SDK at any of those versions is provably readable by the other two.
What “three independent implementations” means
Section titled “What “three independent implementations” means”The SDKs share no code. They are separate implementations of the same specification in three languages, and they must agree byte-for-byte on canonical JSON and hash output and agree on which signatures are valid. Interop is wired as a single shared keypair: the TypeScript SDK is the canonical source of the keypair (sdk/py/tests/fixtures/ts_vectors.json); the Go and Python SDKs generate their own vectors with that same keypair. Because the key is shared, any SDK can verify a receipt any other SDK signed — that is exactly the cross-language property the tests assert.
Results matrix
Section titled “Results matrix”Each row is a frozen vector set. The Go / Py / TS columns mark which implementations consume and verify that set in their test suites. Vector counts are pulled directly from the committed JSON by scripts/conformance_matrix/count.py — they are not hand-typed.
| Vector set | Purpose | Go | Py | TS | Spec version(s) | Vectors |
|---|---|---|---|---|---|---|
| canonicalization | RFC 8785 canonical JSON + receipt-hash agreement | ✓ | ✓ | ✓ | version-independent | 43 |
| emit-failure | emit-failure outcome contract (ADR-0025) | ✓ | ✓ | ✓ | version-independent | 2 |
| malformed (MUST-reject) | negative corpus every verifier MUST reject | ✓ | ✓ | ✓ | version-independent | 7 |
| v0.2.0 | frozen v0.2.0 receipts + chains | ✓ | ✓ | ✓ | 0.2.0 | 3 |
| v0.3.0 | frozen v0.3.0 receipts + chains | ✓ | ✓ | ✓ | 0.3.0 | 3 |
| v0.4.0 | frozen v0.4.0 receipts + chains | ✓ | ✓ | ✓ | 0.4.0 | 2 |
| v0.5.0 | frozen v0.5.0 receipts + chains | ✓ | ✓ | ✓ | 0.5.0 | 3 |
| did:key resolution | did:key v0.7 resolution wire shape (ADR-0007) | — | — | — | did:key v0.7 | 3 |
| disclosure envelope | parameter-disclosure envelope: pinned ciphertext | ✓ | ✓ | ✓ | envelope v1 | 2 |
| rotation event | key-rotation event verifies under the outgoing key | ✓ | ✓ | ✓ | 0.2.1 | 1 |
Each linked vector set above is pinned to an immutable commit, so a citation stays valid as the corpus grows.
CI enforcement
Section titled “CI enforcement”Cross-language verification is enforced in continuous integration, not run by hand. Every pull request and every push to main that touches an SDK, the shared vectors, or the specification runs that SDK’s cross-language suite:
sdk-go.yml— runs the GoCrossLanguageintegration tests, which verify TypeScript- and Python-signed receipts in Go and reject the malformed corpus.sdk-py.yml— runstests/test_cross_language_go.pyandtests/test_cross_language_ts.py, verifying Go- and TS-signed receipts in Python.sdk-ts.yml— runs the TypeScript cross-language suite, verifying Go- and Python-signed receipts in TypeScript.cross-sdk-tests.yml— runs the shared spec-example and version-pinned vector checks, plus the CLI↔WASM verifier gate.
Path filtering scopes each run to the changed surface: a change to the shared vectors or the spec re-runs all three SDK suites; a change confined to one SDK re-runs at least that SDK’s cross-language verification. A regression that breaks interop — a canonicalization drift, a signature-encoding change, a verifier that stops rejecting a malformed receipt — turns a required check red before merge.
Run it yourself
Section titled “Run it yourself”The frozen vectors and the suites that consume them live in the repository. Run each line from the repository root; the per-suite commands use a subshell so the directory change does not leak into the next line:
# Go: verify TS- and Python-signed receipts, reject the malformed corpus(cd sdk/go && go test -tags=integration -v -run CrossLanguage)
# Python: verify Go- and TS-signed receipts(cd sdk/py && uv run pytest tests/test_cross_language_go.py tests/test_cross_language_ts.py -v)
# TypeScript: verify Go- and Python-signed receipts(cd sdk/ts && pnpm test -- cross-language)
# Shared spec-example and version-pinned vector checks(cd cross-sdk-tests && go test -tags=integration -v)
# Regenerate the vector counts in the matrix abovepython3 scripts/conformance_matrix/count.py --format mdSee cross-sdk-tests/README.md for how the shared vectors are generated and consumed.