### The parameter-set pin, specified; component identity; pin-aware selection

- **SPEC §3.1** defines the pin a manifest carries (`conditioning.prior`; a `WAI2`
  rendition's `prior`): `id`, `sha256`, `determinism`, and the optional `form`,
  `tier` and `supersedes`. The digest covers the whole parameter set: a form-less
  pin is admissible only for a capability registered with a one-file set (§5
  registers each capability's shape), and a set of several files is pinned through
  its listing, the new registered prior form `wai.prior.set` (`StandardDefined`,
  royalty-free, the one form listed as established exact). A sink verifies the pin
  before it decodes, reports a refusal with one of an ordered set of snake_case
  reasons (`pin_malformed`, `form_not_registered`, `form_unreadable`,
  `form_required`, `prior_revoked` / `prior_not_authorised` (check 5, run by a sink
  that holds a key log; see *Key discovery, signing authority and module revocation*
  below), `prior_not_held` / `digest_superseded`, `set_malformed`, `part_mismatch`;
  `set_incomplete` during a decode), and decodes only from the set it verified. A pin over a capability this
  revision does not register is verified as several files. `null` in an optional
  member is the same as absent.
- **Tier** is a closed vocabulary (`decode-equivalence`, `entropy-consistency`,
  `none`): an encoder writes a registered token, a sink reads any other as `none`,
  a verifier reports it (`tier_unregistered`). Pins without `tier` keep the legacy
  reading of `determinism`, now stated normatively, so every existing verdict —
  `tests/vectors/int_mlicpp/stream.wai`'s included — is unchanged.
- **`supersedes` is informative**: it changes only the reason a sink that holds the
  predecessor reports, a malformed one is a static finding the sink ignores, and a
  successor never satisfies its predecessor's pin.
- **§4 and §7.1**: a pin that does not resolve makes its capability unsupported for
  that envelope; dispatch continues at the fallback or the next rendition, and an
  inert envelope's error names the reasons: for `WAI1`, the reason kept for the
  capability before the fallback's, `set_incomplete` included; for `WAI2`, every
  entry's (`not_selectable`, `missing_capability`, `component_digest_mismatch`, a
  pin reason, or, under a policy that serves only sound `replicate` claims, the
  entry's `replicate_*` reason). A `WAI1` pin applies to whichever capability
  decodes the payload.
- **Component identity (§7.1)**: a rendition entry MAY carry `id` (unique, never a
  capability string), `sha256` (its payload digest, checked before the entry is
  decoded or applied: `component_digest_mismatch`) and, on a companion,
  `companion_of_id`, which binds it to one entry — an enhancement layer can now
  bind to one of two renditions of a base capability. `id`, `sha256` and `prior`
  are one construct; no extension defines another per-component digest.
- **§7**: `replicate` over a `NeuralIntegerExact` capability MUST carry a pin that
  declares `decode-equivalence`, in no form or in `wai.prior.set`. The new
  *Digests* subsection names SHA-256 for parameter-set identity, for component
  identity, and for the decoded output of capabilities that decode against a
  parameter set and of standard codecs in conformance material; FNV-1a and BLAKE3
  stay as diagnostics. The vectors of such capabilities gain `sha256.json`
  sidecars; no existing vector file or value changes.
- **§8** settles how an optional member is added under the 1.x freeze, which the
  `form` entry below left open: a MINOR revision MAY define an OPTIONAL member,
  envelopes keep `wai` `"1.0"`/`"1.1"`, a reader MUST ignore a member it does not
  understand whatever the MINOR, and an earlier reader may instead reject such an
  envelope (fails closed) or ignore the pin (fails open), which §3.1 states. §8
  states separately the one exception this revision makes to the freeze (next
  entry).
- **Envelopes made non-conforming:** the list in SPEC §3.1. None is committed.
  One kind stops parsing, the one exception to the `1.x` freeze that §8 states: a
  manifest that carries a member this revision defines (a pin or pin member, or a
  rendition entry's `id`, `sha256` or `companion_of_id`) with another JSON type is
  malformed, because reading a mistyped `form` as absent would turn a set-form pin
  into a form-less one. The envelope's `wai` value does not signal it.
  New vectors: `tests/vectors/int_mlicpp/{model.sha256, stream_set.wai}` (the
  set-form twin, written by `tools/wai_int_mlicpp_set_form.py`) and the
  `pin-conformance/` corpus, with an independent verifier in Python.
- **Reference-sink behaviour:** a form-less pin over a several-file capability is
  refused (`form_required`), where before it verified one file or failed on a
  directory; `wai.neural.int_synth`'s pin covers `int_synth.json`; a digest that is
  not 64 lowercase hex is refused, where before it was compared case-insensitively;
  a refused pin falls through to a fallback the registry holds; every decoder reads
  parameters through `neural::ParamSource`, so a pinned decode reads only verified
  bytes (ONNX sessions built from them), and an ONNX model that keeps a tensor's
  data in another file, which the runtime would read from outside those bytes, is
  refused with `set_incomplete` naming that file, as §3.1 now states; `bmshj2018`'s CDF cache is keyed by content
  digest and holds a bounded number of tables, least recently used evicted.
  `decode_envelope_strict` applies §7's rule to the capability it decodes through,
  so a sound fallback behind an unsound primary the sink cannot use still decodes;
  it refuses before reading a file only when every capability it could decode
  through (dispatchable and advertised) is refused, so a candidate the registry
  happens to hold does not change its reason. A `WAI2` parse sums the rendition lengths in 64 bits, so a
  table whose lengths wrap a 32-bit sum is refused as truncated on 32-bit targets
  too, where it used to panic. `wai inspect` prints digests through
  `pin::digest_preview`, which shows a malformed one whole instead of cutting it
  inside a character.
- **Rust API, source-breaking** (the same 0.4.0 release as `form`): the manifest
  types (`Manifest`, `ModelRequirement`, `Conditioning`, `Prior`, `Supersedes`,
  `ManifestV2`, `RenditionMeta`, `Rendition`, `Security`) are now
  `#[non_exhaustive]`, with constructors and `with_*` builders that write the same
  JSON a literal wrote, so the next optional member does not break callers again;
  every manifest object keeps members it does not model (`extra`), and `Manifest`
  gains `security`, so a Rust round trip loses nothing. `Rendition` holds a
  `RenditionMeta`. `Wai::dispatch_capability` is replaced by `dispatch_verified`;
  `WaiMulti::pick`/`primary` take a pin verifier and return `Picked` (index, entry,
  payload, verified set, skipped entries); `companions_of_index` binds by id.
  `DecodeError::PriorMismatch` carries a `PinRefusal`, and `DecodeError` gains
  `NoRendition`; `ModelRegistry` gains `held`/`hold`/`verify`/`resolve_verified`
  (`resolve_checked` is deprecated); new `decode_payload`, `decode_multi`,
  `decode_multi_strict`. `sha2` is now a plain dependency, and the new `pin` module
  needs no feature.
- **C ABI:** a codec-free `ffi` feature carries the envelope surface (`codecs`
  implies it); `WAI_ERR_PRIOR` (5), `WAI_ERR_UNSOUND_REPLICATE` (6) and
  `WAI_ERR_NO_RENDITION` (7), with the reason first in `wai_last_error`; the unpack
  calls return the original manifest bytes, as `wai.h` already documented; the
  `WAI2` table carries identity, pin and `selectable`; new `wai_envelope_select`
  and `wai_neural_decode_ex` (`WAI1` or `WAI2`, a registry of held sets, a strict
  flag), which writes `*out` on every call, empty on failure, so `out->data` is
  always safe to free. The envelope packers build under `ffi` too, and
  `tests/ffi_envelope.rs` checks in CI that they refuse a candidate and that
  `wai_envelope_select` never picks one.
- **wai-web** wraps `wai::container` instead of reduced copies, so `role`,
  `companion_of`, identity and pins reach JS, and exposes `pick`, `companionsOf`,
  `verifyPin` and `sha256Hex`; a component whose capability is not dispatchable
  (SPEC §4) is never presented as media, and `rendition(i)` and `companion(i)` refuse an entry whose payload does not
  match its `sha256`. Its JS-facing tests run under wasm32 in CI.
- **One dispatch predicate:** `dispatch_verified`, `pick`, `primary`,
  `RenditionMeta::is_selectable`, `decode_multi`, `decode_envelope_strict`'s early
  refusal, `wai_envelope_select`, wai-web and `wai inspect` all take a capability only when `codecs::is_dispatchable`
  (above) accepts it, so a candidate, a record or a derivation is never dispatched
  or picked, whatever its pin. An unregistered string stays dispatchable where the
  sink advertises it, and a pin on it is verified as several files, so it fails
  closed. SPEC §7.1 step 2 reads "dispatchable (§4)". `wai.prior.set` has its row in
  the registry table, so `registry/capabilities.json`, `REGISTRY.md` and vocab v2
  list it.
- **Vocabulary:** `vocab/v1` gains the pin terms additively, and `wai registry
  export` writes the same terms and shapes into v2, with the tier list taken from
  `codecs::TIER_TOKENS`; `vocab/check_shapes.py` validates conforming and
  non-conforming pins against the v2 shapes. `sharedPriorUri` and
  `sharedPriorHash` are annotated as not being the manifest pin. The SHACL pin shape
  targets the objects of `wai:prior` (no class is asserted for them), and
  `supersedes` is checked by its own shape: a required digest and an optional form.
- **Open item:** `wai.world.model` names its renderer's model by `model_id`, a
  second model-identity construct; it is to fold into the pin once that renderer
  is registered as decoding against a parameter set.

