{
 "schema_version": "1.3.3",
 "published_at": "2026-09-09T00:00:00Z",
 "publisher": "AliceLabs LLC",
 "description": "Canonical bytes for UTA conformance test vectors. Each vector has its JCS-canonicalized bytes published as hex, base64, and UTF-8 text, alongside the SHA-256. An external verifier can use these to reproduce signature verification without guessing the preimage.",
 "canonicalization_method": "RFC 8785 JCS (JSON Canonicalization Scheme)",
 "vectors": [
  {
   "id": "valid-atc",
   "type": "valid",
   "format": "atc-v2",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 693,
   "sha256": "25b460863524d58579c24ca7bd0184e640d93ba119e51b41b1bdef829f22ece6",
   "sha512": "cce12e43bd60cd38e1fb85aec8ebe5d0e68be4f89c062ecd54a8ba5aa6c5495d064293182f003392134678c6ccd333988e565b8c8ca8ec26b4194cc5b126daaa",
   "bytes_hex_file": "valid-atc.bytes.hex",
   "bytes_base64_file": "valid-atc.bytes.base64",
   "canonical_text_file": "valid-atc.canonical.txt",
   "original_vector_file": "valid-atc.json",
   "signed_at": "2026-08-20T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
   "expected_stages": {
    "signature_verification": "pass",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "pass",
    "status_check": "pass"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key equal the pinned trust anchor ca-test-1. wrong-ca fails the first; self-signed-atc fails the second. A runner that skips the trust_anchor_key_selection comparison (trust-on-first-use) passes self-signed-atc and scores 10/11."
  },
  {
   "id": "valid-atc-2",
   "type": "valid",
   "format": "atc-v2",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 717,
   "sha256": "0f48777e3efa65ca0bb5366dc7a9d088f1a21685be6deb7fbc00205bf36992e3",
   "sha512": "efc267fc39441cd31714a6aa8aa04ea8d67346ca1665c6d188ceefd404ffff1aeb7624d851b86f19ad236233a09f711b37bae7e7e2a4b95730fed0204a1dd27c",
   "bytes_hex_file": "valid-atc-2.bytes.hex",
   "bytes_base64_file": "valid-atc-2.bytes.base64",
   "canonical_text_file": "valid-atc-2.canonical.txt",
   "original_vector_file": "valid-atc-2.json",
   "signed_at": "2026-09-09T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAvtRhFInVXf939xGvD9i6dhBWAAMFjUAA66Qn2KzEWsg=",
   "expected_stages": {
    "signature_verification": "pass",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "pass",
    "status_check": "pass"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key belong to the pinned trust anchor set. wrong-ca fails the first; self-signed-atc fails the second. expiry_check / status_check are policy stages. Stage mismatches count as vector failures per stage_scoring_rule — a runner that fires the wrong stage scores the vector wrong even when its boolean matches.",
   "anti_shortcut": "Second accept card with different agent_id, capabilities, protocol_language, scores, issued_at and expires_at than valid-atc. Both the canonical bytes and the digest move, so a runner that memorizes the single v1.2.0 accept card (hash 25b46086...) cannot recognize this one: acceptance must come from the rule, not from recognition."
  },
  {
   "id": "valid-unknown-field",
   "type": "valid",
   "format": "atc-v2",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 881,
   "sha256": "3f9f9d66fcad436517439b7494019a0dbe1f2f52b96a2aaff88e653b6698592b",
   "sha512": "2c5ea7d6daa70995a8297eb15e24e5db76d670467e1c4f1a6128080bc1ea615a371180c4774383806edaea1bc2c0a3e62c55fb4f74a9c1e62b4c79213791233f",
   "bytes_hex_file": "valid-unknown-field.bytes.hex",
   "bytes_base64_file": "valid-unknown-field.bytes.base64",
   "canonical_text_file": "valid-unknown-field.canonical.txt",
   "original_vector_file": "valid-unknown-field.json",
   "signed_at": "2026-09-09T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAvtRhFInVXf939xGvD9i6dhBWAAMFjUAA66Qn2KzEWsg=",
   "expected_stages": {
    "signature_verification": "pass",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "pass",
    "status_check": "pass"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key belong to the pinned trust anchor set. wrong-ca fails the first; self-signed-atc fails the second. expiry_check / status_check are policy stages. Stage mismatches count as vector failures per stage_scoring_rule — a runner that fires the wrong stage scores the vector wrong even when its boolean matches.",
   "anti_shortcut": "Accept card carrying a permitted x_uta_extension field inside the signed subtree. A runner that over-rejects (rejects cards for unknown-but-permitted fields) fails this vector with a false rejection. Unknown x_* fields are inside the JCS-canonicalized signed document; tolerance is required, not optional."
  },
  {
   "id": "invalid-signature",
   "type": "invalid",
   "format": "atc-v2",
   "expected_verify": false,
   "reason": "tampered signature",
   "canonical_bytes_length": 697,
   "sha256": "12f9a1fb8941370b114fdd4fad39d1e96b11273786ab425c6992ab4e739567f4",
   "sha512": "7c46d59d806d3c45dd84fc0f664bd66e5ff8063d04c73ea4895c1b7b63cb054ad40f8e180b383cf4d45256c482bd1e777a7c9c304a9586420501d8fa388d2a22",
   "bytes_hex_file": "invalid-signature.bytes.hex",
   "bytes_base64_file": "invalid-signature.bytes.base64",
   "canonical_text_file": "invalid-signature.canonical.txt",
   "original_vector_file": "invalid-signature.json",
   "signed_at": "2026-08-20T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
   "expected_stages": {
    "signature_verification": "fail",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "pass",
    "status_check": "pass"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key equal the pinned trust anchor ca-test-1. wrong-ca fails the first; self-signed-atc fails the second. A runner that skips the trust_anchor_key_selection comparison (trust-on-first-use) passes self-signed-atc and scores 10/11."
  },
  {
   "id": "expired-atc",
   "type": "invalid",
   "format": "atc-v2",
   "expected_verify": false,
   "reason": "expired",
   "canonical_bytes_length": 689,
   "sha256": "b7cb5da5c26b2174d2d6167a2b02233fe0baf172686eb3ed4c9b5afea132cc8f",
   "sha512": "8102fcbc36be4dfe37e6d16226381408c12a190e3aa0daa0fa5050d553a26e0752a3213cd826464aa49565e4428068587d20441512d860a897f7d93880dcb25e",
   "bytes_hex_file": "expired-atc.bytes.hex",
   "bytes_base64_file": "expired-atc.bytes.base64",
   "canonical_text_file": "expired-atc.canonical.txt",
   "original_vector_file": "expired-atc.json",
   "signed_at": "2026-08-20T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
   "expected_stages": {
    "signature_verification": "pass",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "fail",
    "status_check": "pass"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key equal the pinned trust anchor ca-test-1. wrong-ca fails the first; self-signed-atc fails the second. A runner that skips the trust_anchor_key_selection comparison (trust-on-first-use) passes self-signed-atc and scores 10/11."
  },
  {
   "id": "premature-atc",
   "type": "invalid",
   "format": "atc-v2",
   "expected_verify": false,
   "reason": "premature — issued_at is in the future (2030-01-01); the lower bound of the validity window fails",
   "canonical_bytes_length": 703,
   "sha256": "e86b08901dcf94c836bdfa1107d92a5564c1e6059b89be18a622bc1131b011b4",
   "sha512": "0d6b034cc81476f24abbca3c9729e11e2c9672c7f5a45e4f8a7bba83479daf0241f6ca9485097ca6447dc9bd57f034ccc67e4daaf07ee970d6dca18b243f081a",
   "bytes_hex_file": "premature-atc.bytes.hex",
   "bytes_base64_file": "premature-atc.bytes.base64",
   "canonical_text_file": "premature-atc.canonical.txt",
   "original_vector_file": "premature-atc.json",
   "signed_at": "2026-09-09T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAvtRhFInVXf939xGvD9i6dhBWAAMFjUAA66Qn2KzEWsg=",
   "expected_stages": {
    "signature_verification": "pass",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "fail",
    "status_check": "pass"
   },
   "expected_stages_doc": "The exact mirror of expired-atc: clean cryptography (signed by ca-test-2, a pinned anchor with a published private key), active status, and a validity window whose ONLY defect is the lower bound — issued_at 2030-01-01 is ahead of the clock. A runner that checks only expires_at accepts this card (always-true, policy-blind, crypto-only, TOFU all do). Added in v1.3.3 in response to anp2network's bug report (dev.to comment 3ec7d): the reference runner previously enforced only the upper bound, so roughly half of the generator's accept-mode cards were dated in the future while the sidecar still declared expiry_check pass — a stricter-than-reference runner was being punished for being right."
  },
  {
   "id": "revoked-atc",
   "type": "invalid",
   "format": "atc-v2",
   "expected_verify": false,
   "reason": "revoked",
   "canonical_bytes_length": 728,
   "sha256": "749f80b69d56a128466cdb54efaa8f4156d7366c705e3bf43d7c85fd326cc379",
   "sha512": "6e565727d70ff5b8635b74b8cb86dc109196500b754c16bcb3cc26535eeb08c7f917cc51092c9735e89ae76168f799dcc8090fe9f58bfa35f31cae3c8e50bf24",
   "bytes_hex_file": "revoked-atc.bytes.hex",
   "bytes_base64_file": "revoked-atc.bytes.base64",
   "canonical_text_file": "revoked-atc.canonical.txt",
   "original_vector_file": "revoked-atc.json",
   "signed_at": "2026-08-20T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
   "expected_stages": {
    "signature_verification": "pass",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "pass",
    "status_check": "fail"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key equal the pinned trust anchor ca-test-1. wrong-ca fails the first; self-signed-atc fails the second. A runner that skips the trust_anchor_key_selection comparison (trust-on-first-use) passes self-signed-atc and scores 10/11."
  },
  {
   "id": "valid-zta",
   "type": "valid",
   "format": "zta",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 499,
   "sha256": "5bc2f576c8f0182bac431e92797d50ac68e8aba21204a57f4d770aafa99ba913",
   "sha512": "435f912364af5b19b89b2e8e79e1eafa7ef3ad25afecd27420eecfded018f56e0bde25be70e4a25d942b2ea2f94d5f75507c51bf2ecfc310792c533eca5d2a07",
   "bytes_hex_file": "valid-zta.bytes.hex",
   "bytes_base64_file": "valid-zta.bytes.base64",
   "canonical_text_file": "valid-zta.canonical.txt",
   "original_vector_file": "valid-zta.json"
  },
  {
   "id": "valid-a2a",
   "type": "valid",
   "format": "a2a-card",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 319,
   "sha256": "270b572585b581ee889c29cb05cc4fea28fe43b3b74ec68b46cd8e2a962b3131",
   "sha512": "867f6aabb5feb87ced934c6d40f7274d67847ec1a5e784a2db3e5ad781fa6c39a4d7735d6479e4bd45e34f821368aeb24f9e92506f01af7400636b569c763de1",
   "bytes_hex_file": "valid-a2a.bytes.hex",
   "bytes_base64_file": "valid-a2a.bytes.base64",
   "canonical_text_file": "valid-a2a.canonical.txt",
   "original_vector_file": "valid-a2a.json"
  },
  {
   "id": "valid-mcp",
   "type": "valid",
   "format": "mcp-card",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 227,
   "sha256": "bb3eb6d4a861017c5713e6e3ebcb0ea8fceb613e28291af70c81926e6711e672",
   "sha512": "7e8ceb0d5d50045ae7a09e2b4482eac7cd57846d51a1f18520fe5366af5a6e7aa715fcb35115a030e2f4d19170618a2d118a75857353030898884487488fae60",
   "bytes_hex_file": "valid-mcp.bytes.hex",
   "bytes_base64_file": "valid-mcp.bytes.base64",
   "canonical_text_file": "valid-mcp.canonical.txt",
   "original_vector_file": "valid-mcp.json"
  },
  {
   "id": "atc-to-uts",
   "type": "translation",
   "format": "?",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 957,
   "sha256": "8415c5ae43198866231cb55bfe7a61973baed6b38a887cfd318b25d1ced0e5a4",
   "sha512": "80a64ac6828c4791e993088c197eaae9c1858d0b4917f19ec0184e6f303180b8398c514d4474c6f752160de33874c2b80b7fa4029343790b7c2f60d7eb2925db",
   "bytes_hex_file": "atc-to-uts.bytes.hex",
   "bytes_base64_file": "atc-to-uts.bytes.base64",
   "canonical_text_file": "atc-to-uts.canonical.txt",
   "original_vector_file": "atc-to-uts.json"
  },
  {
   "id": "uts-to-zta",
   "type": "translation",
   "format": "?",
   "expected_verify": true,
   "reason": "",
   "canonical_bytes_length": 437,
   "sha256": "f8e041e4b4a17f85a01841673065de8970bf90f8d892b9ca92b83af7ed902faa",
   "sha512": "fa2eadf1abf0ffc47c3e799968e1d77e7fd2cc65e864a4aad0a4592a031316367d0a6722cb30b887dc68967fcab97fc6eccfeec91f12477b25e7ca2b31ae0d0b",
   "bytes_hex_file": "uts-to-zta.bytes.hex",
   "bytes_base64_file": "uts-to-zta.bytes.base64",
   "canonical_text_file": "uts-to-zta.canonical.txt",
   "original_vector_file": "uts-to-zta.json"
  },
  {
   "id": "wrong-ca",
   "type": "invalid",
   "format": "atc-v2",
   "expected_verify": false,
   "reason": "signed-by-wrong-ca-key",
   "description": "Real Ed25519 signature by a second throwaway CA, embedded key claims the published test CA. Anti-shortcut vector: metadata looks fully valid (active, unexpired); only actual signature verification can fail this card.",
   "canonical_bytes_length": 705,
   "sha256": "8c71acbc3875007c7954f632ceea4b7c08b627fcaec451459b17ab5683a26f83",
   "sha512": "cce648acd5a2724f9937ce772adb863d39ef9eb4d992eb24a06e2723d60a7dbe605f698dfdf9412a7f86f433dc90142dfa5c23569eb574985e758a04a6f6ad51",
   "bytes_hex_file": "wrong-ca.bytes.hex",
   "bytes_base64_file": "wrong-ca.bytes.base64",
   "canonical_text_file": "wrong-ca.canonical.txt",
   "original_vector_file": "wrong-ca.json",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
   "signed_at": "2026-09-08T00:00:00Z",
   "expected_stages": {
    "signature_verification": "fail",
    "trust_anchor_key_selection": "pass",
    "expiry_check": "pass",
    "status_check": "pass"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key equal the pinned trust anchor ca-test-1. wrong-ca fails the first; self-signed-atc fails the second. A runner that skips the trust_anchor_key_selection comparison (trust-on-first-use) passes self-signed-atc and scores 10/11."
  },
  {
   "id": "self-signed-atc",
   "type": "invalid",
   "format": "atc-v2",
   "expected_verify": false,
   "reason": "self-signed-untrusted-key",
   "description": "Real Ed25519 signature by a throwaway attacker key (ca-self-1) that the card DECLARES in payload.identity.public_key and signs with. Cryptographically self-consistent and metadata-clean: signature verification against the declared key PASSES, expiry/status PASS. Only the pinned trust-anchor comparison (declared key != ca-test-1) fails it. Anti-shortcut vector for key selection: an embedded-key (trust-on-first-use) runner returns true here. Requested by anp2network (dev.to, 2026-09-08): the untested twin of wrong-ca. wrong-ca = \"claims the right key, signed by someone else\"; self-signed-atc = \"claims its own key, signed with it\".",
   "expected_stages": {
    "signature_verification": "pass",
    "trust_anchor_key_selection": "fail",
    "expiry_check": "pass",
    "status_check": "pass"
   },
   "expected_stages_doc": "Per-stage expected outcomes. signature_verification: does the signature verify against the key the card DECLARES (self-consistency of the crypto). trust_anchor_key_selection: does the declared identity.public_key equal the pinned trust anchor ca-test-1. wrong-ca fails the first; self-signed-atc fails the second. A runner that skips the trust_anchor_key_selection comparison (trust-on-first-use) passes self-signed-atc and scores 10/11.",
   "canonical_bytes_length": 717,
   "sha256": "7b04ee78363a28b69ed82b8b62356cfb568ad8799abab357f25c86a5cea364ba",
   "sha512": "30a01fe918f98700486163dc69081564b2d21c1b922f46180131a0906c99719cdd0bcef2701e6271bf82920597936d858ca163c5412112f2e98cf8192bf2458d",
   "bytes_hex_file": "self-signed-atc.bytes.hex",
   "bytes_base64_file": "self-signed-atc.bytes.base64",
   "canonical_text_file": "self-signed-atc.canonical.txt",
   "original_vector_file": "self-signed-atc.json",
   "signed_at": "2026-09-08T00:00:00Z",
   "signed_subtree": "whole-document-minus-signature",
   "signature_algorithm": "Ed25519 (RFC 8032) over JCS(RFC 8785) canonical bytes",
   "ca_public_key_spki_b64": "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
   "attacker_key_spki_b64": "MCowBQYDK2VwAyEAQXK5aLmUiJqQ1Tkc87DfXn+k+j44a0AWlitxiiBO/uo=",
   "attacker_key_file": "ca-self-1.pub.spki.b64",
   "attacker_key_note": "ca-self-1 is the key the card declares AND signs with. Verifiers pinning ca-test-1 fail this card by design. Verifiers trusting the embedded key pass it by mistake — that is the point."
  }
 ],
 "updates": [
  "v1.1.0 — Signed all ATC vectors with a real throwaway Ed25519 CA (ca-test-1). Public key published beside the vectors (SPKI base64 + raw 32 bytes). Added wrong-ca anti-shortcut vector (real signature from a second CA). Added per-vector signed_subtree field. Previously the vectors carried placeholder signatures (0xab bytes) and a truncated 12-byte SPKI header, so no verifier could actually verify. Response to anp2network (dev.to comment 3e1j6, 2026-09-02).",
  "v1.2.0 — Added self-signed-atc (attacker key declared in identity.public_key AND used to sign; metadata clean). Separates pinned-CA runners from embedded-key/trust-on-first-use runners, which both scored 10/10 on v1.1.0. Added machine-readable expected_stages per signed vector (signature_verification / trust_anchor_key_selection / expiry_check / status_check): expected_verify alone folded signature validity with policy validity. Existing 10 vectors are UNCHANGED byte-for-byte. Response to anp2network (dev.to, 2026-09-08): \"The shortcut you killed at signature verification came back one level up, at key selection.\"",
  "v1.3.0 — Response to anp2network (dev.to, 2026-09-08): \"the accept side is one card\" + over-rejection unpunished + expected_stages not actually scored. (1) Added valid-atc-2, a second handwritten accept card with different agent_id, capabilities, scores, protocol_language, issued_at, expires_at — canonical bytes and digest both move, so acceptance comes from the rule, not recognition. (2) Added valid-unknown-field, an accept card carrying a permitted x_uta_extension field — punishes over-rejecting runners (false rejections read as healthy on a reject-heavy suite). (3) Added the generator: ca-test-2 with its PRIVATE KEY PUBLISHED in _test-ca-keys.json, plus generate-accept-vectors.mjs producing unlimited fresh accept/self-signed/wrong-ca cards with random x_gen_* fields. Any fixed set is memorizable; a generator is not. ca-test-1 was frozen (its throwaway private key was discarded at generation time, so no second ca-test-1-signed card can ever exist — which is exactly why the generator CA had to be a new key), and the pinned anchor set is now {ca-test-1, ca-test-2}. (4) Added stage_scoring_rule + the reference scorer tests/conformance/score-runner.mjs: stage mismatches count as vector failures, killing the stage-liar runner that fails everything at signature_verification. The 11 v1.2.0 vectors are UNCHANGED byte-for-byte — all previously published verification results still hold.",
  "v1.3.1 — Closes the two remaining items from the thread: (1) reproducible source-tree rebuild for agent-trust-card@1.1.2 tarball (tarball-rule.json + verify-rebuild.mjs, byte-for-byte tar-layer identity); (2) third-party digest anchoring via Sigstore public Rekor (external_anchors + verify-rekor.mjs, replaces the retracted signed-tag wording, issue #13).",
  "v1.3.2 — Response to the recognized follow-up: \"making the runner the tested thing, not just the cards.\" The reference scorer is our code; until now a stranger had to trust it. Now the runner is the test SUBJECT: (1) answer-key.json pins its observable behavior (the 8-runner separation matrix + the reference-mode verdict, row by row, failure lists included), recorded as of 2026-09-09 and valid through 2027-08-19 — the day before the earliest future vector expiry; the suite fails closed after that, it never silently passes on stale expectations. (2) runner-tests.mjs re-derives the whole thing from the live runner: bytes check, matrix parsing, row-by-row comparison, reference-mode exit code. (3) 10 deterministic mutants of the runner (stage-blind, memorizer-promote, score-inflate, anchor-narrow, expiry-blind, status-blind, sig-accept-all, translation-flip, stage-liar-cured, over-rejector-cured — each a byte patch with occurrence-checked targets and a pinned digest) must EACH diverge from the key: a key nothing can fail is not a test, and here every mutant is caught. (4) The runner bytes, answer key, suite, mutants and this index evolution are countersigned into Sigstore public Rekor as a second entry (throwaway P-256, private key discarded after signing, same policy as ca-test-1). The behavioral oracle is the key; the bytes oracle is Rekor; between them the runner is neither trusted nor untested. Live: https://www.marketnow.site/uta/conformance/runner-tests/",
  "v1.3.3 — Response to anp2network's second bug report (dev.to comment 3ec7d, 2026-09-08T21:35Z), which confirmed v1.3.0/v1.3.1 closed the three original gaps and then found two new problems — one of them caused by the stage scoring added in v1.3.0: (1) the generator drew the issue year as 2026|2027 with random month/day, so ~half of accept-mode cards were dated ahead of the clock (seed 7, count 60: 32/60) while the sidecar declared expiry_check pass; the reference runner checked only expires_at and never read issued_at — one side of the validity window. Fixed both sides: the generator now DERIVES issued_at from the wall clock (clamped 1..729 days into the past, expires_at = issued_at + 3 years) and fail-closes at generation if the window is violated; the reference runner now enforces issued_at <= NOW < expires_at; and this vector, premature-atc, closes the lower bound of the FIXED suite the way expired-atc closes the upper bound. (2) expected_verify for generated cards defaulted to true when _generated-index.json was missing, so deleting that one unsigned sidecar inverted the scoring (self-signed 4-card set: always-true 0/4→4/4, reference 4/4→0/4). Fixed by DERIVING ground truth from the card bytes and the pinned anchors: the sidecar is demoted to a cross-check (a sidecar that disagrees with the derived truth is a hard FATAL), a missing sidecar no longer changes any expectation, and a true-by-default inversion is impossible. Rerun evidence with the same seed 7 / count 60 and the same self-signed 4-card set is in the article thread."
 ],
 "signed_subtree_rule": "The signature covers the JCS-canonicalized document with its top-level \"signature\" key removed. The identity.public_key inside payload is part of the signed subtree and MUST equal ca-test-1 for verify=true.",
 "test_ca": {
  "name": "ca-test-1 (throwaway, vectors-only, NEVER used in production)",
  "algorithm": "Ed25519 (RFC 8032)",
  "public_key_spki_b64": "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
  "public_key_raw32_hex": "807f035abe60faead5e6ce69b8aac621fd76eb37e5e0a32a46ed02ffa610e09d",
  "public_key_files": [
   "ca-test-1.pub.spki.b64",
   "ca-test-1.pub.raw32.hex",
   "ca-test-1.pub.raw32.b64"
  ],
  "wrong_ca_note": "ca-wrong-1.pub.spki.b64 is the key that signs the wrong-ca vector. Verifiers must use ca-test-1 and will fail wrong-ca by design.",
  "self_signed_note": "ca-self-1.pub.spki.b64 is the attacker key of the self-signed-atc vector (declared AND signing). ca-wrong-1.pub.spki.b64 signs the wrong-ca vector while it claims ca-test-1. Both fail under a ca-test-1-pinned verifier, at different stages."
 },
 "key_selection_rule": "verify=true REQUIRES payload.identity.public_key to be a member of the pinned trust anchor set (see pinned_trust_anchors.anchors) and the signature to be produced by that same member key. A card that declares and signs with its own key (self-signed-atc) is self-consistent cryptography with an untrusted anchor: verify=false. A card that claims a pinned anchor but is signed by someone else (wrong-ca) fails signature verification: verify=false. Skipping the membership comparison is trust-on-first-use and fails self-signed-atc.",
 "pinned_trust_anchors": {
  "rule": "verify=true REQUIRES payload.identity.public_key to be a member of the pinned set AND the signature to be produced by that member key.",
  "anchors": [
   "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=",
   "MCowBQYDK2VwAyEAvtRhFInVXf939xGvD9i6dhBWAAMFjUAA66Qn2KzEWsg="
  ],
  "anchor_notes": {
   "MCowBQYDK2VwAyEAgH8DWr5g+urV5s5puKrGIf126zfl4KMqRu0C/6YQ4J0=": "ca-test-1 — frozen v1.2.0 anchor. Private key was discarded at generation time (single-session throwaway). No new card can ever be signed by it: the six v1.2.0 signed vectors are its complete output.",
   "MCowBQYDK2VwAyEAvtRhFInVXf939xGvD9i6dhBWAAMFjUAA66Qn2KzEWsg=": "ca-test-2 — generator CA, private key PUBLISHED in _test-ca-keys.json. Produces valid-atc-2, valid-unknown-field, and unlimited fresh cards via generate-accept-vectors.mjs."
  },
  "why_two": "The pinned set grew by exactly one key, and the reason is the accept-side hole: ca-test-1 cannot sign a second accept card ever again (its private key no longer exists), so the second card and the generator required a second anchor. Membership semantics are unchanged: self-signed and wrong-ca still fail key selection or signature verification against the set."
 },
 "stage_scoring_rule": "Per-stage scoring is part of the suite, not a note. For every vector carrying expected_stages, a runner must report its per-stage outcomes, and the runner vector is compared stage by stage: any stage mismatch marks the vector FAILED even when the runner boolean matches expected_verify. This kills the stage-liar runner (fails everything at signature_verification): it still reports the right boolean for expired-atc and revoked-atc, but its stage vector is wrong on 3 of 4 stages for both, so both score as failures. See tests/conformance/score-runner.mjs for the reference implementation.",
 "unknown_field_rule": "Cards MAY carry extension fields (keys prefixed x_ inside payload). Extension fields are inside the signed subtree — JCS canonicalizes them, the signature covers them. A runner MUST tolerate unknown x_* fields: rejecting a card because of an unknown-but-permitted field is a false rejection. valid-unknown-field and every generator card with x_gen_* fields test this. Rationale: over-rejection reads as healthy on a reject-heavy suite (10/11 while choking on a permitted field) and is the mirror failure of always-true.",
 "generator": {
  "file": "generate-accept-vectors.mjs",
  "run": "node generate-accept-vectors.mjs --count 20 [--seed 42] [--mode accept|self-signed|wrong-ca] [--out DIR]",
  "ca": "ca-test-2 (private key in _test-ca-keys.json)",
  "purpose": "Unlimited fresh signed cards. Accept mode: random agent_id, agent_name, capabilities, scores, expiry, and random x_gen_* extension fields, all signed by ca-test-2 — acceptance must come from the rule, not recognition, and no fixed set can be memorized. self-signed / wrong-ca modes produce unlimited REJECT challenges the same way.",
  "determinism": "--seed makes generation reproducible (seeded PRNG); without it, crypto-random. v1.3.3: issued_at/expires_at are derived from the wall clock (1..729 days back, +3 years), never from the PRNG — a generated card can never be dated ahead of NOW, and the generator fail-closes if it ever is."
 },
 "reproducible_build": {
  "rule": "The npm artifact agent-trust-card@1.1.2 is rebuildable from the source tree: the source files, transformed by tarball-rule.json (12 entries, fixed order and metadata, LF→CRLF, publisher JSON serialization for package.json), reproduce the tarball's uncompressed tar layer byte-for-byte.",
  "tarball_sha256": "f1b44ed29eea0ca9eee65c1e0974c5d2b4b512378c6d21edb6344daf9184641a",
  "tar_layer_sha256": "519d406adba1e8199ca0c91a8f47195a81e42745aac05e599c9b3de87359b990",
  "source_manifest_sha256": "5665c19bbfef0212c99ad1a5e156e8b265f3c5a9df05317f21775c34188e20e0",
  "rule_file": "https://www.marketnow.site/uta/conformance/repro/tarball-rule.json",
  "verify_command": "node verify-rebuild.mjs --manifest source-manifest.json",
  "live": [
   "https://www.marketnow.site/uta/conformance/repro/build-agent-trust-card.mjs",
   "https://www.marketnow.site/uta/conformance/repro/verify-rebuild.mjs",
   "https://www.marketnow.site/uta/conformance/repro/tarball-rule.json",
   "https://www.marketnow.site/uta/conformance/repro/source-manifest.json",
   "https://www.marketnow.site/uta/conformance/repro/agent-trust-card-1.1.2.tgz"
  ]
 },
 "external_anchors": {
  "rule": "The digests below are countersigned and timestamped by a third party (Sigstore public Rekor, rekor.sigstore.dev) in an append-only, inclusion-checkable transparency log. The publisher cannot rewrite an entry once committed. This replaces the retracted \"signed Git tag\" anchoring (issue #13).",
  "rekor": {
   "log": "https://rekor.sigstore.dev",
   "entry_uuid": "108e9186e8c5677a91a6963aa1e9125a7350c84e5018e60e6d374db7117011c1f67e8b4c5bf420e0",
   "log_index": 2762061972,
   "tree_log_index": 2640157710,
   "integrated_time": "2026-09-08T21:03:33Z",
   "entry_url": "https://rekor.sigstore.dev/api/v1/log/entries?logIndex=2762061972",
   "countersignature": "ECDSA P-256 over sha256(anchor statement), throwaway key, private key discarded after signing"
  },
  "anchored": {
   "agent-trust-card-1.1.2.tgz": "f1b44ed29eea0ca9eee65c1e0974c5d2b4b512378c6d21edb6344daf9184641a",
   "agent-trust-card-1.1.2 tar layer (rebuild target)": "519d406adba1e8199ca0c91a8f47195a81e42745aac05e599c9b3de87359b990",
   "source manifest (12 files)": "5665c19bbfef0212c99ad1a5e156e8b265f3c5a9df05317f21775c34188e20e0",
   "conformance vectors _index.json v1.3.0": "358a18d58aaef16c3c64a2622404d88d8af67e1cb6c31ea76dac12626eab7597"
  },
  "verify_command": "node verify-rekor.mjs --record anchor-record.json --statement anchor-statement.json (entry #1) | --record anchor-record-v2.json --statement anchor-statement-v2.json (entry #2, runner under test) | --record anchor-record-v3.json --statement anchor-statement-v3.json (entry #3, two-sided window + derived ground truth)",
  "live": [
   "https://www.marketnow.site/uta/conformance/anchors/anchor-statement.json",
   "https://www.marketnow.site/uta/conformance/anchors/anchor-record.json",
   "https://www.marketnow.site/uta/conformance/anchors/verify-rekor.mjs"
  ],
  "rekor_v2": {
   "log": "https://rekor.sigstore.dev",
   "entry_uuid": "108e9186e8c5677ae6e6afcebd3785524b9b2702b100b3b38b1e2a2f10a7c7d4056023cd4dd1e53a",
   "log_index": 2764017355,
   "tree_log_index": 2642113093,
   "integrated_time": "2026-09-09T01:14:24Z",
   "entry_url": "https://rekor.sigstore.dev/api/v1/log/entries?logIndex=2764017355",
   "statement_canonical_sha256": "dfda2410a2f9a8283730b31c1d5201f3fb1baae3f346a15ce1c149e28380f750",
   "countersignature": "ECDSA P-256 over sha256(anchor statement v2), throwaway key, private key discarded after signing",
   "note": "entry #2 anchors the runner-under-test artifacts (v1.3.2). Entry #1 above remains the historical anchor for v1.3.0 digests."
  },
  "anchored_v2": {
   "score-runner.mjs": "ef5fd5fbc003e27caef523f8b0395953190e9fc6ac88009c2131ea6cc33a23b8",
   "runner-tests/answer-key.json": "9ccd874428e6db852d8cdc106dd516642a253c9a666326ebfdb31518217a442a",
   "runner-tests/runner-tests.mjs": "6960d4070c2ac2c4a59056536a5beef603c9a9171f993a2d1274b8f114723914",
   "runner-tests/mutants.json": "a23b19fbef01d8664d4b14e0b4dc993138a83b5bda9b785e6915f083ee92d929",
   "runner-tests/README.md": "c1880604aa932202d0e7e9ea741520b9bea7a7dca217e5cf4fa90ad49cd6f436",
   "_index.json (v1.3.1, pre-release state)": "ee9de8535b9498624b60e578496c5970291ff20ad1e9bae20f9f3496c6303da1"
  },
  "rekor_v3": {
   "log": "https://rekor.sigstore.dev",
   "entry_uuid": "108e9186e8c5677afa82e19ae0b973f8534ef7af35ee1e346ed149ce4b0342367eee31912d996850",
   "log_index": 2764479676,
   "integrated_time": "2026-09-09T02:26:31.000Z",
   "entry_url": "https://rekor.sigstore.dev/api/v1/log/entries?logIndex=2764479676",
   "countersignature": "ECDSA P-256 over sha256(anchor statement), throwaway key, private key discarded after signing",
   "statement_sha256": "0b1913c6b30311333357f3d9629ae69ea7d10b7cbd19ac64833889a3c20e0f60",
   "subject": "two-sided validity window + derived generated-card ground truth + premature-atc (v1.3.3) — fixes anp2network bug report 3ec7d"
  },
  "anchored_v3": {
   "score-runner.mjs (v1.3.3, two-sided window + derived expectations)": "deec4cf670bed7b30eae0995b15c1c08970c29e3e72087329e0544aaf85aa972",
   "generate-accept-vectors.mjs (v1.3.3, clock-derived issue dates)": "5688cf90c83aa833d636ac169664ebd6031ea7a26e965b99248cf649128313c6",
   "premature-atc.json (fixed vector #14, issued 2030-01-01)": "68e6fc56102776e8e9ba35f86d6ca7144e664b2a90f9be51de82d94ce72fab96",
   "premature-atc canonical bytes": "e86b08901dcf94c836bdfa1107d92a5564c1e6059b89be18a622bc1131b011b4",
   "runner-tests/answer-key.json (re-recorded 2026-09-09, 14 vectors)": "4063919bd4e3b118973cc2694d8c069ef24f8fa24d4cf9b0c77f4267e983c738",
   "runner-tests/runner-tests.mjs (24 checks)": "e8454eb5b2c0323ef0678058b27d9607282376cdb6f79a7bd73a637db1c6502e",
   "runner-tests/mutants.json (10 mutants, updated occurrences)": "9f082e251920b477407c6f299f7fc941e20e026dcafcb88dde2db27621f0cc46",
   "runner-tests/README.md (v1.3.3)": "066f189fb9425d0386428255be303ccda31d27af82290f6d18862c1811e4a0c9",
   "conformance vectors _index.json v1.3.2 (pre-release state)": "pinned inside the Rekor statement, served from raw.githubusercontent @3e3fdbb7"
  }
 },
 "runner_under_test": {
  "rule": "The reference scorer (score-runner.mjs) is a tested component, not a trusted one: its bytes are pinned by digest (answer key, itself anchored in Rekor), its observable behavior must reproduce the pinned answer key exactly (separation matrix + reference verdict), and a 10-mutant suite proves the key has teeth — every known-bad runner variant diverges and is caught. v1.3.3: the validity window is two-sided (issued_at <= NOW < expires_at) and generated-card ground truth is DERIVED from card bytes + pinned anchors — the sidecar is a cross-check, never the source of truth. After valid_until the suite fails closed instead of passing on stale expectations.",
  "runner": "score-runner.mjs",
  "suite": "runner-tests/runner-tests.mjs",
  "answer_key": "runner-tests/answer-key.json",
  "mutants": "runner-tests/mutants.json",
  "mutant_count": 10,
  "as_of": "2026-09-09",
  "valid_until": "2027-08-19",
  "fail_closed": "after valid_until the suite exits non-zero with an explanation — vectors must be re-issued and the key re-anchored",
  "verify_command": "node runner-tests/runner-tests.mjs",
  "live": [
   "https://www.marketnow.site/uta/conformance/runner-tests/runner-tests.mjs",
   "https://www.marketnow.site/uta/conformance/runner-tests/answer-key.json",
   "https://www.marketnow.site/uta/conformance/runner-tests/mutants.json",
   "https://www.marketnow.site/uta/conformance/score-runner.mjs"
  ],
  "runner_sha256": "deec4cf670bed7b30eae0995b15c1c08970c29e3e72087329e0544aaf85aa972",
  "answer_key_sha256": "4063919bd4e3b118973cc2694d8c069ef24f8fa24d4cf9b0c77f4267e983c738",
  "suite_sha256": "e8454eb5b2c0323ef0678058b27d9607282376cdb6f79a7bd73a637db1c6502e",
  "mutants_sha256": "9f082e251920b477407c6f299f7fc941e20e026dcafcb88dde2db27621f0cc46",
  "readme_sha256": "066f189fb9425d0386428255be303ccda31d27af82290f6d18862c1811e4a0c9",
  "v1_3_3": "answer key re-recorded 2026-09-09 after the two-sided window fix (14 fixed vectors incl. premature-atc); mutant occurrence counts updated for the derived-expectation code paths (anchor-narrow 4, expiry-blind 5, status-blind 5, sig-accept-all 5); runner window scan now also tracks earliest future issued_at. All 24 checks pass, 10/10 mutants caught, reference 14/14."
 },
 "validity_window_rule": "A card is inside the validity window only if issued_at <= NOW < expires_at — BOTH bounds. expiry_check covers the whole window: expired-atc fails the upper bound (expires 2020-01-01), premature-atc fails the lower bound (issued 2030-01-01). A runner that checks only one side accepts the other's vector and is scored wrong for it. Before v1.3.3 the lower bound was unimplemented in the reference runner and untested by the suite (anp2network, comment 3ec7d): the generator had no opinion to disagree with."
}
