{ "suite": "action-ref-v1-jcs-sha256", "version": "1.0", "spec": "../../docs/specs/action-ref-v1.md", "description": "Conformance vectors for the cross-ecosystem action_ref v1 correlation key. Accept vectors carry the expected lowercase-hex SHA-256 of the RFC 8785 JCS canonicalization of the four-field preimage; every expected value was generated by the SDK implementation (computeExternalActionRefV1). Reject vectors carry reject:true and must fail the timestamp grammar rather than be coerced.", "vectors": [ { "id": "av-001", "description": "Basic happy path. Minimal tuple with a DID agent_id and a zero-millisecond timestamp written in full.", "input": { "agent_id": "did:aps:zExampleAgent001", "action_type": "document.sign", "scope": "repo:example/docs", "timestamp": "2026-06-09T12:00:00.000Z" }, "canonical": "{\"action_type\":\"document.sign\",\"agent_id\":\"did:aps:zExampleAgent001\",\"scope\":\"repo:example/docs\",\"timestamp\":\"2026-06-09T12:00:00.000Z\"}", "expected": "f5cc735aa740b1a5006bf4d41f6e3cacbabcab3e369043b58d924e3bb69b4988" }, { "id": "av-002", "description": "Second basic vector: did:web agent_id and a non-zero millisecond timestamp.", "input": { "agent_id": "did:web:example.org:agents:42", "action_type": "calendar.create_event", "scope": "calendar:work", "timestamp": "2026-01-15T08:30:45.123Z" }, "canonical": "{\"action_type\":\"calendar.create_event\",\"agent_id\":\"did:web:example.org:agents:42\",\"scope\":\"calendar:work\",\"timestamp\":\"2026-01-15T08:30:45.123Z\"}", "expected": "baae7b7a8ab833556cffdfbf199bd77cc9b88f41f5ad75a02edee0f5429c1b55" }, { "id": "av-003", "description": "Unicode in action_type and scope (Cyrillic plus an emoji). JCS does not normalize Unicode; the UTF-8 bytes of the literal strings are hashed.", "input": { "agent_id": "did:aps:z6MkUnicodeAgent", "action_type": "розрахунок.підпис", "scope": "scope:звіт/📄", "timestamp": "2026-06-09T12:00:00.500Z" }, "canonical": "{\"action_type\":\"розрахунок.підпис\",\"agent_id\":\"did:aps:z6MkUnicodeAgent\",\"scope\":\"scope:звіт/📄\",\"timestamp\":\"2026-06-09T12:00:00.500Z\"}", "expected": "a99472d9b5ce07b8d977fc217452361df5b137af66d40bd03639bee4caa2b158" }, { "id": "av-004", "description": "Key-order independence. The same tuple presented in three different JSON key orders canonicalizes to one byte sequence and one hash (identical to av-001). Verifiers parse each variant and recompute.", "input": { "agent_id": "did:aps:zExampleAgent001", "action_type": "document.sign", "scope": "repo:example/docs", "timestamp": "2026-06-09T12:00:00.000Z" }, "input_json_variants": [ "{\"agent_id\":\"did:aps:zExampleAgent001\",\"action_type\":\"document.sign\",\"scope\":\"repo:example/docs\",\"timestamp\":\"2026-06-09T12:00:00.000Z\"}", "{\"timestamp\":\"2026-06-09T12:00:00.000Z\",\"scope\":\"repo:example/docs\",\"action_type\":\"document.sign\",\"agent_id\":\"did:aps:zExampleAgent001\"}", "{\"scope\":\"repo:example/docs\",\"agent_id\":\"did:aps:zExampleAgent001\",\"timestamp\":\"2026-06-09T12:00:00.000Z\",\"action_type\":\"document.sign\"}" ], "canonical": "{\"action_type\":\"document.sign\",\"agent_id\":\"did:aps:zExampleAgent001\",\"scope\":\"repo:example/docs\",\"timestamp\":\"2026-06-09T12:00:00.000Z\"}", "expected": "f5cc735aa740b1a5006bf4d41f6e3cacbabcab3e369043b58d924e3bb69b4988" }, { "id": "av-005", "description": "Timestamp edge: last millisecond before midnight rollover, maximum fractional value .999.", "input": { "agent_id": "did:aps:z6MkRollover", "action_type": "ledger.append", "scope": "audit:write", "timestamp": "2025-12-31T23:59:59.999Z" }, "canonical": "{\"action_type\":\"ledger.append\",\"agent_id\":\"did:aps:z6MkRollover\",\"scope\":\"audit:write\",\"timestamp\":\"2025-12-31T23:59:59.999Z\"}", "expected": "eff6e891f28538747e7021159214094ec57a22e31a2d2f9a1a5850513f1e65ad" }, { "id": "av-006", "description": "Timestamp edge: first instant after midnight rollover, .000 milliseconds written in full (zero fractional digits are not omitted).", "input": { "agent_id": "did:aps:z6MkRollover", "action_type": "ledger.append", "scope": "audit:write", "timestamp": "2026-01-01T00:00:00.000Z" }, "canonical": "{\"action_type\":\"ledger.append\",\"agent_id\":\"did:aps:z6MkRollover\",\"scope\":\"audit:write\",\"timestamp\":\"2026-01-01T00:00:00.000Z\"}", "expected": "d1a07a866fe3fd376433a9d6d459e66033e58a32c77d675cc2d884497ff5529c" }, { "id": "av-007", "description": "Empty-string scope. The empty string is a valid scope value and is load-bearing in the preimage.", "input": { "agent_id": "did:aps:z6MkEmptyScope", "action_type": "noop.ping", "scope": "", "timestamp": "2026-03-15T08:45:30.123Z" }, "canonical": "{\"action_type\":\"noop.ping\",\"agent_id\":\"did:aps:z6MkEmptyScope\",\"scope\":\"\",\"timestamp\":\"2026-03-15T08:45:30.123Z\"}", "expected": "cea68656343a06fad083af9a283329af96fcbc6c5fa183229823070fe635641b" }, { "id": "av-008", "description": "Long scope string (588 characters). No length-dependent behavior in canonicalization or hashing.", "input": { "agent_id": "did:aps:z6MkLongScope", "action_type": "data.derive", "scope": "data:cohort/segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789", "timestamp": "2026-02-28T23:00:01.042Z" }, "canonical": "{\"action_type\":\"data.derive\",\"agent_id\":\"did:aps:z6MkLongScope\",\"scope\":\"data:cohort/segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789segment-0123456789\",\"timestamp\":\"2026-02-28T23:00:01.042Z\"}", "expected": "2158e331d3b6b8cfcfc8a7235c3f03018fe2582491bc2f8761eb85f3aa91f5ff" }, { "id": "rj-001", "description": "Lowercase t separator is invalid.", "input": { "agent_id": "did:aps:z6MkReject", "action_type": "noop.ping", "scope": "s", "timestamp": "2026-05-24t10:30:00.000Z" }, "reject": true, "reason": "timestamp separator must be uppercase T; RFC 3339 lowercase t is not the canonical action_ref form" }, { "id": "rj-002", "description": "Lowercase z suffix is invalid.", "input": { "agent_id": "did:aps:z6MkReject", "action_type": "noop.ping", "scope": "s", "timestamp": "2026-05-24T10:30:00.000z" }, "reject": true, "reason": "timestamp suffix must be uppercase Z; lowercase z is not the canonical action_ref form" }, { "id": "rj-003", "description": "Explicit +00:00 offset is invalid even though it denotes UTC.", "input": { "agent_id": "did:aps:z6MkReject", "action_type": "noop.ping", "scope": "s", "timestamp": "2026-05-24T10:30:00.000+00:00" }, "reject": true, "reason": "only the Z suffix is accepted; numeric offsets are rejected rather than normalized, one valid byte sequence per instant" }, { "id": "rj-004", "description": "Missing fractional seconds (second precision) is invalid.", "input": { "agent_id": "did:aps:z6MkReject", "action_type": "noop.ping", "scope": "s", "timestamp": "2026-05-24T10:30:00Z" }, "reject": true, "reason": "exactly three fractional digits are required; a second-precision timestamp is rejected rather than padded" }, { "id": "rj-005", "description": "Six fractional digits (microsecond precision) is invalid.", "input": { "agent_id": "did:aps:z6MkReject", "action_type": "noop.ping", "scope": "s", "timestamp": "2026-05-24T10:30:00.000000Z" }, "reject": true, "reason": "exactly three fractional digits are required; extra precision is rejected rather than truncated" } ] }