Live Verification

action-ref-v1 Conformance

Vectors fetched from action-ref-verify. Digests computed server-side via JCS (RFC 8785) + SHA-256. Nothing hardcoded.

repo updated 2026-05-28 | revalidates hourly

Why this matters

When an AI agent pays for a service, nothing currently proves what the agent did after payment. The action_ref binds a payment to a specific action through a deterministic, re-derivable hash. For this to work across implementations, every party must produce identical hashes from identical inputs. This page verifies that property live against the published vector set.

12
Vectors (live)
12/12
Conformant

Live verification results

VectorExpectedLiveDigest (first 16)Notes
giskard-baselinePASSCONFORMANTfdd7f810499f06be...First independent verification of action-ref-v1. Source: x402-foundation/x402#2332
ms-precision-trapFAILCONFORMANT999919e8b69846be...Timestamp drops millisecond precision (.000Z -> Z). Semantically identical time, but JCS treats strings as opaque bytes. Correct hash for this input is 999919e8b69846be116934c9ca3f72eaef6d54aac5ab17f1a6b050cae7bda197, not the baseline hash. Implementations that normalize timestamps before hashing will produce the wrong action_ref.
trailing-whitespaceFAILCONFORMANT37caadb35cfdedf1...Trailing space in action_type. JCS preserves string content exactly. Implementations that trim whitespace before canonicalization will silently produce a different hash. Correct hash for this input is 37caadb35cfdedf144827b121e004c81b471c7f22120eb372707c1814699427e.
extra-field-ignoredPASSCONFORMANTfdd7f810499f06be...Extra field in preimage object. The verifier extracts only the 4 canonical fields (action_type, agent_id, scope, timestamp) before canonicalization. Extra fields are ignored. This is the correct behavior: action_ref is computed from the canonical 4 fields, not from the full input object. Implementations that include extra fields in the JCS input will produce a DIFFERENT hash. Open question: should the spec explicitly require field extraction, or should it hash the full object? This vector tests that our verifier handles the extraction correctly.
key-order-resiliencePASSCONFORMANTfdd7f810499f06be...Keys in reverse order. JCS sorts lexicographically regardless of insertion order. This MUST produce the same hash as the baseline. Implementations that hash insertion-order JSON instead of canonicalized JSON will fail this test.
rfc8785-negative-zeroPASSCONFORMANTd7a591f6afb04565...Tests that the JCS implementation handles standard preimage fields. RFC 8785 requires -0 to serialize as 0. This vector validates the canonicalization pipeline end-to-end with a simple, known-good input.
rfc8785-key-sorting-stressPASSCONFORMANTfdd7f810499f06be...Same preimage as giskard-baseline but with keys in reverse alphabetical order. RFC 8785 Section 3.2.3 requires lexicographic key sorting. JCS must produce identical canonical bytes regardless of input key order. This is the most critical RFC 8785 property for action_ref correctness.
x402-2357-shared-fixturePASSCONFORMANT10d8a38c01d86721...Three-way interop vector from x402-foundation/x402#2357. Shared payment_hash and action_ref bind Axis 1 (seritalien/zkpay STARK), Axis 2 (feedoracle hybrid-PQC ES256K+ML-DSA-65), and Axis 3 (this harness). Uses timestamp_ms (epoch integer) per the original #2332 preimage spec. JCS canonicalization (RFC 8785) produces identical bytes across Node.js, Python, and Rust runtimes.
field-name-load-bearingFAILCONFORMANT89a312bc953f7bac...Same semantic instant as 0008 (1747728000000 ms = 2025-05-20T00:00:00.000Z) but using timestamp (RFC 3339 string) instead of timestamp_ms (epoch integer). JCS treats field names as opaque bytes: 'timestamp' and 'timestamp_ms' produce different canonical output and different digests. This vector MUST FAIL against the 0008 action_ref, proving the field name is load-bearing. Implementations that normalize between the two forms before hashing will produce silent interop failures.
duplicate-key-rejectionFAILCONFORMANT5c013729a078f46c...Proposed by seritalien (Vauban Pay). JSON RFC 8259 Section 4 admits duplicate keys with parser-dependent behavior. Last-wins vs first-wins produce different canonical bytes. This vector uses agent_id 'agent-a' which differs from the baseline 'agent-7', so the digest does not match. Verifiers MUST reject duplicate-key inputs at parse before canonicalization. The raw duplicate-key input (not representable in standard JSON) would be: agent_id appears twice with values agent-a and agent-b.
unicode-nfd-divergencePASSCONFORMANT24d6bd1693f44c42...Proposed by seritalien (Vauban Pay). RFC 8785 performs no Unicode normalization. The e-acute character can be encoded two ways: NFC pre-composed (U+00E9, 2 UTF-8 bytes c3 a9) producing digest 24d6bd16..., or NFD decomposed (e + U+0301, 3 UTF-8 bytes 65 cc 81) producing digest 5c775958.... This vector uses NFC. Real-world sources (macOS HFS+, some databases) silently normalize, which would change the digest.
required-field-missingFAILCONFORMANT2c0b510091f2b72b...Proposed by seritalien (Vauban Pay). agent_id is absent from the preimage. JCS canonicalizes any well-formed JSON without schema validation, producing a valid but meaningless digest (2c0b5100...). The digest does not match the baseline because the canonical output differs. Verifiers MUST require presence of all canonical fields before canonicalization.

Method

Derivation: action_ref = SHA-256(JCS(preimage))

Canonicalization: RFC 8785 (JCS)

Timestamp: timestamp_ms (epoch integer)

Field names: load-bearing opaque bytes

Independent reproductions

Node.js: action-ref-verify v0.3.0

Rust: vauban-zkpay-x402 (serde_jcs 0.2.0)

Python: FeedOracle (rfc8785 0.1.4)

4-lang: AlgoVoi (Python/JS/Go/Java)

Verify API

Submit an action receipt and get a conformance verdict.

curl https://verify.crestsystems.ai/health

curl -X POST https://verify.crestsystems.ai/v1/verify \
  -H "Content-Type: application/json" \
  -d '{
    "action_ref": "<sha256-hex>",
    "preimage": {
      "action_type": "...",
      "agent_id": "...",
      "scope": "...",
      "timestamp_ms": 1747728000000
    }
  }'

Vectors are fetched live from GitHub and verified server-side. Reports describe conformance at render time, not cached assertions.

Maintained by Crest Deployment Systems