### Key discovery, signing authority and module revocation

- [`extensions/jwp-receipts.md`](extensions/jwp-receipts.md) §7: a signer can say
  where its keys are published, and a verifier can confirm it. A `signer_id` of the
  form `did:web:<host>[%3A<port>]#<key-id>` names a web origin, which publishes at
  `/.well-known/wai-keys` a **key log**: revisions signed by a root key that
  pre-commits to its successor, each listing the origin's keys, the authorities each
  holds (`delivery`, `energy/<acquisition class>`, `lawful-basis/declaration` or
  `/decision`, `log-inclusion`, `soft-binding`, `binding-recovery`, `measurement`,
  `operating-point`, `receipt`, `module/decoder`, `module/reconstruct`) and whether it
  is active, retired or revoked. The path is published now; its registration in the IANA Well-Known URIs
  registry is to be requested. A `did.json` on the same origin SHOULD list exactly
  the log's active keys, and the log governs.
- A verifier that has anchored the origin — pinned out of band, or fetched from the
  origin over HTTPS and recorded as such — confirms an accepted receipt, claim or
  module grant against the log, offline, and reports `confirmed`, `refused` or
  `unconfirmed` with a named reason beside the item's own verdict, never folded into
  it. An item needs every authority the item fixes: a group receipt needs `delivery`
  and `energy/<class>` for each class its objects' labelled leaves and its labelled
  total carry, another family's receipt `receipt` and `energy/<class>` for each class
  its figures carry, a claim its class's authority, and an energy authority is read from any
  `energy_provenance` a claim's body carries, whatever its class — so a `measurement`
  or `operating-point` claim needs its class's authority and the energy authority of
  the figure it restates, pinned-only for a hardware class. An Ed25519 `did:key`
  names one key, and one naming a key other than the signer's is refused; a `did:key`
  longer than any Ed25519 key's spelling is a label, refused before it is decoded. The head walk
  ignores revisions that are not held, unattached, or signed by a key their parent
  does not authorise; the owner's rotation supersedes a stolen root's revisions; an
  older log retrieved after a newer one was anchored is reported as rolled back.
- Pinned-only authorities: the hardware-class energy authorities and the
  lawful-basis authorities, and any authority registered for pre-emption, are
  confirmed only under a pinned anchor that has not moved (`anchor_not_pinned`);
  every confirmation reports whether its anchor was pinned or fetched. A pinned record
  moved forward by a later retrieval stays pinned and keeps the revision that was
  pinned, and a pre-emption authority is read from that revision only. Beside an item
  that needs a hardware-class authority, a verifier reports whether its key also
  holds `delivery` (`also_delivers`); the recommendation that it not is a SHOULD.
- Revocation refuses every item under a revoked key, whatever time the item carries.
  A retired key's untimed items stay confirmable until the key is revoked, and are
  reported as untimed.
- §7.9, decoder and reconstruct modules: a module, or a parameter set an envelope
  pins, is identified by the SHA-256 of its bytes and authorised by a signed **module
  grant** from a key holding `module/<form>`, for named capabilities and a bounded
  window. A grant is held only from one of the sink's **module origins** — an origin
  its relying party names, or the origin under which it confirmed the envelope's
  delivery — so anchoring an origin for its receipts does not make it a source of
  modules. The key log revokes modules by digest (`revoked_modules`, append-only), and
  a digest revoked in the head of any origin the sink has anchored is not held,
  whichever origin grants it. Each log declares `grant_max_s` and `status_max_age_s`
  under normative ceilings; a signed **key status** from the head's root, re-issued on
  each heartbeat and held only if it names the head or an ancestor of it, keeps a sink
  current. Eight ordered checks decide whether a sink runs a module; every failure —
  including no network, a stale status and no trusted clock — means the module is not
  held, and dispatch falls back: a sink never reports a file inert because of module
  authorisation while a fallback remains, and an encoder whose capability needs a
  module declares one. The kill latency `grant_max_s + status_max_age_s` is a
  normative parameter. The ceilings are 86400 s for `grant_max_s` and 3600 s for
  `status_max_age_s`.
- Module revocation through the parameter-set pin. [`SPEC.md`](SPEC.md) §4 folds the
  hook into its steps: a sink that runs a module obtained apart from an envelope holds
  it under §7.9, or the capability is not advertised for that envelope. SPEC §3.1's
  check 5, reserved until now, runs at a sink that holds a key log, keyed on the pin's
  `form` and `sha256`, before check 6. It has two parts. Revocation runs for every
  capability a pin applies to and needs no grant, status or clock: a set whose digest
  the head the sink reaches from any anchor it holds revokes is refused with
  `prior_revoked`, whichever check a grant would fail first. Authorisation runs where
  the relying party holds the capability's pinned sets to §7.9, its choice per
  capability: §7.9 authorises the set as a decoder module, and any other failure,
  offline and no grant included, is `prior_not_authorised`. Dispatch moves to the
  fallback as for any refused pin. An envelope that pins no set does not escape check
  5: the set an unpinned decode reads is checked under each digest a pin over it could
  name. A sink configured with no key log does not run check 5.
  `key_log::module_check` implements §7.9's checks; `key_log::SinkKeyLog` runs check 5
  in the reference dispatcher, given to `pin::verify_with` or to
  `neural::ModelRegistry::with_key_log`, which also runs it before an unpinned decode.
  Library tests in CI dispatch a revoked set to its fallback, report `prior_revoked`
  when none remains, refuse a revoked set whose grant fails an earlier check, whose
  sink holds no grant, or whose capability is not held to §7.9, and fall back when the
  sink is offline; the neural sink gates run the same refusals through
  `neural::decode_envelope` over the committed int_mlicpp set, pinned and unpinned. A
  key log that names the subject's origin holds for one envelope, so a registry given
  one decodes that envelope only. The reference dispatcher runs no module obtained
  apart from an envelope; `wai-web` and the C ABI take no key log.
  `neural::ModelRegistry` gains a private field, so a struct literal no longer builds
  one; build it with `ModelRegistry::new()` and its builder methods.
- `wai-rs`: `signer_id` (ungated, no dependency) reads a `signer_id`;
  `key_log` (feature `key_discovery`, no new dependency, checked to build for wasm32)
  implements §7. Outside the crate, an item to confirm is read from bytes that
  verified: `Item::from_claim` from an accepted claim, `Item::from_group` from a group
  receipt and the objects included under it, `Item::from_family` from another
  family's receipt through its figure view, given the `signer_id` and signed time the
  same receipt carries. `wai-keys` builds an origin's key log from seeds the operator names,
  appends retirements, revocations, revoked modules and rotations, signs statuses and
  module grants, verifies a log as §7.3 anchors one — afresh, or as a later retrieval
  against a fetched or pinned anchor already held — and emits and checks a `did.json`.
  It creates no key material, never prints a seed, and refuses a published test key
  unless told the log is a test log.
- `signer-conformance/`: a corpus of anchoring, confirmation and module vectors with
  declared verdicts, generated and verified by `wai_signer_vectors` in CI on every
  platform of the conformance matrix, with a canonical fixture computed by a separate
  implementation (`signer_verify.py`), which also reproduces every vector's verdict. CI
  runs it on the linux runner and requires its verdicts to equal `wai_signer_vectors`'
  line for line (jwp-receipts §5.8).
- No wire format or committed signed vector changes. Every receipt and claim verifies
  as before, and every vector of the claim corpus, those of the `measurement` and
  `operating-point` classes included, keeps its outcome. The reference meters, whose seeds are published, now write a label as
  `signer_id` rather than a real origin, so their signed output differs from before;
  the world demo's signer is a label too. A CI test holds every `did:web` literal in
  a tracked `.rs`, `.json` or `.js` file under `wai/` (`signer-conformance/` aside)
  that names a domain, and every origin-bound one, to a reserved example name. `wai-quantum-serve`'s `/verify`
  reports the signer's level beside validity.
- transparency §6 pointed to "jwp-receipts §7" when no §7 existed; it now points at
  this section. SPEC §6.2–§6.3, confidentiality §6–§7 and jwp-receipts §6.6 no longer
  say that a relay signs, or that checking a receipt needs no key: it needs the
  signer's verifying key, which the receipt carries. prior-carriage §6 no longer says
  WAI has no key discovery.
- Not done here: a key log for `wai-web` and the C ABI; an independent time that could
  reinstate an item signed before its key was compromised; sub-delegation between
  module grants; an authority for pre-emption, relay attestation or reconciliation,
  which have no class; checking a log's evidence under its profile; the keys an OER
  receipt is checked with.

