# WAI Extension: Prior Carriage

> Status: Draft. Registers the wire **forms** a pin's digest may cover —
> `wai.prior.set`, the listing of a parameter set ([SPEC.md §3.1](../SPEC.md)),
> the tensor files `wai.prior.safetensors` and `wai.prior.gguf` (§9), and
> ISO/IEC 15938-17 (neural-network coding, "NNC") — registers a **candidate**
> general-tensor payload, and fixes how an in-band signature inside such an
> artifact relates to WAI's digest. §10 defines the integer-quantised profile
> `wai-int/1`, through which a prior carried in a tensor file or in NNC loads, bit
> for bit, into the native artifact an integer kernel reads; §11 the digest rule; §12
> the NNC reader and writer and where they stop. The pin itself, its verification and
> its refusal reasons are SPEC.md §3.1. Reference impl: `wai-rs` —
> `container::{Prior, PinRefusal}`, `pin::{verify_bytes, verify, parse_listing,
> write_listing, listing_of_dir}`, `codecs::prior_form`,
> `codecs::{CAP_PRIOR_SET, CAP_PRIOR_SAFETENSORS, CAP_PRIOR_GGUF, CAP_PRIOR_NNC,
> CAP_TENSOR_NNC}`, and `prior_wire` (feature `prior_wire`) for §9 to §14; corpus
> [`live-conformance/prior-forms/`](../live-conformance/prior-forms/), second
> implementation `live-conformance/prior_forms_verify.py`. §15 to §19 say where a set is
> fetched and how it travels: set roots and location hints, a successor coded against its
> predecessor as an RFC 9842 dictionary, when a set is worth holding, the usage statement, and
> two more registered forms, `wai.prior.sealed` (a set released by key) and `wai.prior.tree` (a
> set verified per piece); reference `prior_carriage` (feature `prior_carriage`), corpus
> [`live-conformance/prior-carriage/`](../live-conformance/prior-carriage/), second
> implementation `live-conformance/prior_carriage_verify.py`.
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.

## 1. A prior has a digest, and had no form

A neural capability decodes against a parameter set the envelope does not carry
([SPEC.md §1](../SPEC.md)). WAI pins that set's identity
([SPEC.md §3.1](../SPEC.md)): a pin names an `id`, a `sha256` over the whole
parameter set and a `determinism` description, and MAY state a `tier` and the set
it `supersedes`. A sink verifies the pin before it decodes, refuses a pin its sets
do not satisfy with a named reason, and `replicate` soundness is gated on the
declared tier (SPEC §7).

The digest fixes **which bytes**. Until now nothing fixed **what those bytes
are**: the sink hashes whatever single file it registered — a serialized graph,
an integer table bundle — so two implementations can hold the same network under
different digests, or agree on a digest while reading the bytes differently.
A determinism tier is a claim about reproducing a computation; the computation's
operand needs a form both ends can name.

## 2. The `form` field

```json
"prior": {
  "id":          "int_hyper/q4",
  "sha256":      "<64 lowercase hexadecimal digits: the SHA-256 of the set, in its declared form>",
  "determinism": "int-rans/p16+int-synth",
  "form":        "wai.prior.set",
  "tier":        "decode-equivalence"
}
```

- `form` is OPTIONAL. Absent, the form is undeclared and the digest covers the
  one file that holds the parameter set; SPEC §3.1 admits that only for a
  capability registered with a one-file set, and a sink refuses such a pin over
  any other capability (`form_required`). A manifest without `form` round-trips
  byte for byte.
- Present, `form` MUST be a registered prior form (§3), and `sha256` MUST be
  computed over the parameter set serialized in exactly that form: for a coded
  form, the coded bitstream, not an unpacking or a transcoding of it; for
  `wai.prior.set`, the listing SPEC §3.1 defines, never the files' bytes
  concatenated or an archive of them.
- A sink that does not know the declared form as a prior form refuses the pin
  (`form_not_registered`), and one that cannot read it refuses it
  (`form_unreadable`, SPEC §3.1). It MUST NOT resolve the pin against an artifact
  in another form, even one whose unpacked parameters compare equal: equality
  after unpacking is a different fact from the digest the manifest pins.
- A declared form names a **self-contained** parameter set. An NNC
  incremental-update bitstream decodes only against its base, so it MUST NOT be
  pinned on its own, and no form is registered for a base-plus-updates chain. A
  pin names the self-contained set an update yields, and MAY name the set it
  replaced in `supersedes` (SPEC §3.1).
- A form is a capability string. When a prior artifact travels in a WAI envelope
  it does so under its form's capability, so the envelope's per-object content
  hash and the `Prior` digest cover the same bytes.

## 3. Registered form and candidate payload

| capability | payload | status |
|---|---|---|
| `wai.prior.set` | the listing of a parameter set of one or more files (SPEC §3.1) | registered; WAI-native; established exact (§5) |
| `wai.prior.safetensors` | a parameter set as one safetensors file: an 8-byte header length, a JSON header naming each tensor's type, shape and bytes, the tensors' bytes (§9.1) | registered; established exact (§5) |
| `wai.prior.gguf` | a parameter set as one GGUF version 3 file: key-value metadata, tensor descriptions, aligned tensor data (§9.2) | registered; established exact (§5) |
| `wai.prior.sealed` | a one-file set encrypted under a key its origin releases: the inner form, the key's identifier, the counter block, the plaintext's SHA-256, the set's usage statement, then the set under AES-128 in counter mode (§18.2) | registered; WAI-native; established exact (§5) |
| `wai.prior.tree` | the head of a chunk tree over a one-file set: the inner form, the set's length, SHA-256 and BLAKE3 hash, and the BLAKE3 chaining value of each piece (§19) | registered; WAI-native; established exact (§5) |
| `wai.prior.nnc` | the parameters of a trained network as a bitstream conforming to **ISO/IEC 15938-17:2024** (NNC, 2nd edition: parameters and their incremental updates, DeepCABAC entropy coding) | registered; a coded form |
| `wai.tensor.nnc` | general tensorial data — split-inference feature maps, 3D/4D scene parameters — coded with NNC | **candidate**: payload format not fixed |

`wai-rs` reads and writes the NNC subset of §12 (integer tensors under the
standard's arithmetic coding, raw 32-bit floats) and refuses the rest, quantised
payloads among them, with a named reason; otherwise the NNC entries are
sink-supplied. The standard's reference software is itself standardized, in **ISO/IEC 15938-18**,
*Conformance and reference software for compression of neural networks* (1st
edition 2023, 2nd edition 2025). That part also supplies the conformance
bitstreams and the procedures for testing decoders and bitstreams. Its scope
makes the software an integral part of it, gives the requirements of
ISO/IEC 15938-17 precedence over the software's behaviour, and does not require
an implementation to use it.

Registry classification (`codecs::capability_*`):

- **`wai.prior.set`**: fidelity tier lossless and replicate class
  `StandardDefined` — a listing is its own output, and SPEC §3.1 fixes its bytes
  exactly; licence royalty-free (WAI-native, Apache-2.0 reference).
- **`wai.prior.safetensors`, `wai.prior.gguf`**: fidelity tier lossless and
  replicate class `StandardDefined` — a reader that follows §9 hands over each
  tensor's bytes as the file holds them, and §9 leaves no choice of which bytes
  those are; licence royalty-free (the safetensors layout is published with its
  reference implementation under Apache-2.0, GGUF under MIT).
- **`wai.prior.sealed`**: fidelity tier lossless and replicate class `StandardDefined` —
  opened under its key, it hands over the inner set's bytes, checked against the SHA-256 its
  header states (§18.2); licence royalty-free (WAI-native, over AES-128, FIPS 197, in counter
  mode, NIST SP 800-38A).
- **`wai.prior.tree`**: fidelity tier lossless and replicate class `StandardDefined` — it hands
  over the set it names, every piece checked against the head and the whole against the SHA-256
  the head states (§19); licence royalty-free (WAI-native, over BLAKE3).

For the NNC entries:

- **Fidelity tier: lossy, by primary role.** The registry's tier names a
  capability's primary role, as it does for AVIF, which also has a lossless mode;
  it is not a statement that every NNC artifact approximates its source. NNC's
  primary role is compressing a network by parameter reduction and quantisation.
  The published standard is not quantisation-only, though. The 2022 edition
  defines an NNR unit as carrying compressed or uncompressed network data. Its
  table of contents lists decoding methods for an integer payload type
  (`NNR_PT_INT`) and a raw-float payload type (`NNR_PT_RAW_FLOAT`), and a decoding
  process for an integer weight tensor. Those decoding clauses were not read, and
  neither was the 2024 edition. An open implementation that states compliance
  with the 2024 edition reads an `NNR_PT_RAW_FLOAT` payload as raw 32-bit floats
  and passes int32 tensors through with no quantisation step. So an integer
  network, or a float network carried raw, need not be approximated at all.
  Lossy is kept because a capability-level `lossless` would present every NNC
  artifact as reproducing its source, and whether a given artifact does depends
  on its payload types, and on the decoding process of §5.
- **Licence: patent-pool, conservatively.** Royalty status is not established.
  The Introduction of ISO/IEC 15938-17:2022 records a patent claimed to be
  required for compliance, whose holder has given a
  reasonable-and-non-discriminatory licensing assurance; the corresponding
  statement in the 2024 edition was not read. No royalty-free commitment was
  found, and an openly available implementation that states compliance with the
  2024 edition is released under a licence that expressly grants no patent rights
  (see the research note in §8). The registry places NNC where it places MPEG-I
  Haptics for the same reason, and never presents it as royalty-free.
- **Replicate class: the class the registry gives a standard whose decoder
  conformance it has not checked**, as it gives MPEG-I Haptics. The tensors are
  reconstructed by the standard's decoding process, not by a model WAI runs, and
  NNC's decoder conformance (§5) was not read, so nothing here establishes that
  every conforming decoder reconstructs bit-identical tensors. A registry that has
  one class for every standard codec gives NNC that class, which then says only
  that the named standard specifies the reconstruction. This concerns an NNC
  payload. How a declared form bounds `replicate` over a neural capability is §5.

**`wai.tensor.nnc` is a candidate.** Coding of general tensorial data is part of
an NNC amendment that has not been published (§4), so this payload's format is
not fixed. Until the capability is pinned to a published edition, an encoder
MUST NOT emit it and a sink MUST treat it as unsupported. SPEC §5
(*Candidate capabilities*) states the rule for every candidate, and
`codecs::is_candidate` lists them. SPEC §8's rule that a
registered payload format never changes applies from the edition it is pinned to.
It is registered now because split-inference feature maps and scene tensors are a
payload class WAI otherwise has no name for. For Gaussian-splat attributes
specifically, `wai.splat.int_codec` is the path with a portable hash
(splat-equivalence); `wai.tensor.nnc` would be an interchange form with no
determinism guarantee.

## 4. What is pinned, what is tracked, and why `form` is optional

The standard is at two different stages, and WAI treats them differently.

**Pinned — the published editions.** ISO/IEC 15938-17 is a published
International Standard: 1st edition 2022, 2nd edition 2024. `wai.prior.nnc` is
defined against the 2nd edition. Incremental-update coding is in that edition;
it is not new, and an implementation MUST NOT describe it as forthcoming.

**Tracked, not pinned — the amendment.** MPEG's press release for its 154th
meeting (Santa Eulària, 27 April – 1 May 2026) states that a Committee Draft of
an amendment to NNC was published. It adds lossless compression, including mixed
lossy and lossless compression in one bitstream; source-data-type indication for
models with limited bit depth; finer-grained configuration of the quantisation;
configurable extensions for initialising, ordering and packing data; coding of
other tensorial data, such as split-inference feature maps and the parameters of
3D and 4D scene representations; and signing and verification of data units,
which the release says lets a verifier check the authenticity of a set of
network parameters, part of a network, or an update. The amendment's text was
not read, so what a data-unit signature covers and how its key is identified are
not known here. A committee draft can still change. No rule in this extension
depends on any of it. When a published edition carries these features:

- it gets a **new** capability string — SPEC §8 forbids redefining
  `wai.prior.nnc`;
- `wai.tensor.nnc` is pinned to that edition, or withdrawn;
- nothing about exactness changes by that alone. Integer and raw-float payload
  types are already in the published text (§3). What decides whether a form can
  be listed as exact is the decoding process and its conformance requirement
  (§5), for any edition, lossless compression included.

**Optional, not recommended.** `form` is MAY, and NNC is not a SHOULD, for three
reasons:

1. WAI treats royalty-free implementation as a precondition for adoption (SPEC
   Appendix C). It does not recommend, for every prior, a form whose royalty
   status it cannot establish.
2. WAI's reference implementation (`wai-rs`) reads and writes only the subset of
   NNC that §12 states, written from an open implementation rather than from the
   standard's clauses, so it cannot demonstrate the form end to end.
3. Whether conforming NNC decoders reconstruct identical tensors is not
   established (§5), so the form cannot yet carry WAI's strongest claims.

## 5. Determinism through a form

- Declaring a form does not change the prior's `determinism` contract, which
  still states how the network's own decode reproduces.
- Reading an artifact out of a coded form is itself a decode. For a quantised
  payload, NNC's entropy decode produces integer quantisation indices, which the
  decoding process turns into parameter values. An integer or raw-float payload
  carries its values without quantisation (§3). Whether every conforming decoder
  reconstructs bit-identical parameter values, from any of these payload types,
  was not established here. So an integer-exact network can still reach two sinks
  as different weights.
- Where that would be settled: ISO/IEC 15938-18 states that decoder conformance
  to ISO/IEC 15938-17 is specified in clause 7 of 15938-17 (headed *Decoding
  process* in the 2022 edition), and supplies reference bitstreams and a decoder
  test procedure (15938-18 §4.5). Neither clause 7 nor that procedure was read,
  so whether conformance requires identical reconstructed parameters, or permits
  a tolerance, is open. What was read, in the 2022 edition's public sample:
  its scope requires only a decoder's externally observable output to conform;
  its number conventions define `float` by ISO/IEC 60559 and make operator
  results mathematically exact unless a float result is explicitly specified;
  and its clause 7 includes decoding methods for integer, float and raw-float
  payload types. Clause 7 is where a form would be established exact, for the
  published editions and for any later one.
- Therefore an envelope with `intent = replicate` MUST NOT rest on a prior whose
  declared form is not established exact. The registry lists the forms that are
  established (`codecs::prior_form::form_reconstruction_is_exact`). It lists five.
  `wai.prior.set`: reading a set through its listing compares digests and hands
  the decoder each file's bytes unchanged, so every sink that holds the set reads
  the same parameters. `wai.prior.safetensors` and `wai.prior.gguf`: a reader that
  follows §9 finds each tensor's bytes where the file's header puts them and hands
  them over unchanged, and §9 refuses every file whose header could be read two
  ways. `wai.prior.sealed`: opening it under its key is a function of its bytes and the key,
  the plaintext is checked against the SHA-256 the header states, and its inner form is a
  capability's one file, `wai.prior.safetensors` or `wai.prior.gguf` (§18.2). `wai.prior.tree`:
  every piece is checked against the head and the whole set against the SHA-256 the head
  states, and its inner form is one of those three or a sealed set
  (§19). No coded form is listed: within the subset of §12 the integers an NNC reader
  obtains are a function of the bits (§12.4), but the form also covers quantised
  payloads, whose reconstruction is the open question above. In the reference implementation the rule is part of
  `Prior::is_cross_hardware_exact`, which requires `Prior::form_preserves_exactness`
  as well as an integer-exact contract. Every `replicate` check reads that
  predicate, so `container::replicate_is_sound` and `Wai::replicate_is_sound`
  reject such a `replicate`, and `decode_envelope_strict` refuses it with a reason
  naming the form.
- The same bound applies to the tiers of
  [determinism-tiers](determinism-tiers.md): `decode-equivalence` needs identical
  tensors at every sink, so it cannot be claimed through a form not established
  exact.
- The digest is unaffected. It is computed over bytes, so it is portable whatever
  the reconstruction does.

## 6. In-band data-unit signatures and WAI's digest

MPEG's press release for its 154th meeting states that the NNC amendment adds
signing and verification of data units (§4). Its text was not read, and nothing
here depends on its details. This section fixes the precedence now, so the two
cannot diverge later. It takes the posture
[reconstruction-binding](reconstruction-binding.md) takes toward a C2PA manifest:
WAI's binding sits beside the standard's, never in place of it.

- **Scope.** `Prior.sha256`, and a [JWP](jwp-receipts.md) per-object content
  hash over a `wai.prior.nnc` or `wai.tensor.nnc` payload, cover **every byte** of
  the coded bitstream, including any unit that carries an in-band signature.
  Neither is computed over a subset chosen by an in-band signing scope.
- **An in-band signature is an attested input.** A verifier MAY check it and MAY
  record the verdict in a receipt, naming the signature scheme and the key
  location as found. The verdict never substitutes for the WAI digest check. A
  matching WAI digest attests that these are the bytes the manifest pinned; an
  in-band signature attests that a key holder signed these units. Neither implies
  the other.
- **A failed in-band signature is recorded as failed.** It does not unpin a prior
  whose WAI digest matches: the pinned artifact is the one that carries the bad
  signature.
- **Stripping is not repackaging.** Removing signature units changes the bytes,
  so the result no longer matches its pin. It is a different artifact.
- **Keys.** WAI's key discovery ([jwp-receipts](jwp-receipts.md) §7) covers the
  signers of WAI's own receipts and claims, and who may authorise a pinned
  parameter set (jwp-receipts §7.9). A key location found in-band in a prior
  artifact is outside it: it is recorded, not trusted, and never an anchor
  (jwp-receipts §7.3).

## 7. Reference implementation

- `container::Prior` has the members of SPEC §3.1; `form`, `tier` and
  `supersedes` are serde-skipped when absent, so a pin written without them
  round-trips byte for byte, and a member this revision does not define is kept
  (`extra`). `Prior` is `#[non_exhaustive]`: it is built with `Prior::new` and
  the `with_form`, `with_tier` (a typed `codecs::DeclaredTier`, so the crate
  writes only a registered token) and `with_supersedes` builders, so a member a
  later revision adds does not break code that builds one. `Prior::check_syntax`
  applies SPEC §3.1 check 1, `Prior::supersedes_finding` the `supersedes` rule,
  and `Prior::declared_tier` reads `tier` or, without it, the reading SPEC §7
  fixes (`Prior::determinism_class`). `container::PinRefusal::code()` is the
  reason SPEC §3.1 names. `Wai::check_pin` and `WaiMulti::check_pins` report what
  a verifier can decide without holding a parameter set.
- `pin::verify_bytes` runs SPEC §3.1's checks in order over parameter sets held in
  memory (a browser sink calls it); `pin::verify` reads held files and listings
  from disk, keeps the bytes it hashed, and calls it. `pin::parse_listing`,
  `pin::write_listing` and `pin::listing_of_dir` read and write a listing.
  `pin::READABLE_FORMS` holds `wai.prior.set`: the reference sink reads no coded
  form.
- `pin::verify_bytes_with` and `pin::verify_with` run SPEC §3.1's check 5 with a
  `pin::PinAuthority`, before any held file is read. `key_log::SinkKeyLog`
  (feature `key_discovery`) is the one in this crate: built from the key log a
  sink holds, it runs jwp-receipts §7.9 over the pinned sets of the capabilities
  the sink's relying party holds to it. Without one, check 5 is skipped.
- `neural::ModelRegistry` holds, for each capability, its registered path and any
  further paths given to `hold`. For a form-less pin it hashes each held file —
  for `wai.neural.int_synth`, the `int_synth.json` beside it. For a
  `wai.prior.set` pin it takes every `*.sha256` file directly inside each held
  path's directory (the path itself if it is a directory) as a listing rooted
  there. `ModelRegistry::with_key_log` gives it a key log for check 5.
- `container::Wai::dispatch_verified` applies SPEC §4 steps 3–6 and
  `container::WaiMulti::pick` SPEC §7.1 steps 2 and 5, each with a pin verifier
  the caller supplies. `neural::decode_envelope` and `neural::decode_multi`
  decode through them; their strict variants apply SPEC §7 to the capability they
  decode through.
- The decoders read parameters only through `neural::ParamSource`, which hands a
  pinned decode the verified bytes; ONNX sessions are built from those bytes, and
  a file the verified set lacks is refused with `set_incomplete`. The integer
  capabilities decode through `int_payload::decode_int`, which reads its set members
  from memory; `int_payload::resolve` verifies a pin over sets held in memory and
  runs check 5, pinned or unpinned ([integer-payloads](integer-payloads.md) §12).
  `wai.neural.bmshj2018` caches its CDF tables by content digest.
- The C ABI (`ffi`) returns each manifest as its original bytes, carries a `WAI2`
  rendition's identity and pin in the rendition table, and reports a refused pin
  as `WAI_ERR_PRIOR` with its reason first in `wai_last_error`;
  `wai_neural_decode_ex` decodes a `WAI1` or `WAI2` envelope against a registry of
  held sets. The browser crate (`wai-web`) wraps the same types and exposes `pick`,
  `companionsOf` and `verifyPin` to JS.
- CI: the library unit tests cover `container`, `codecs` and `pin`;
  `wai_pin_vectors verify ../pin-conformance` checks the corpus, and
  `pin-conformance/pin_verify.py`, which shares no code with `wai-rs`, checks it
  independently; the model-free neural-sink and neural C ABI tests, and the
  browser crate's tests (natively and under wasm32), are configured to run in CI.
- `prior_wire` (feature `prior_wire`): `safetensors`, `gguf` and `nnc` read a file
  into a `TensorSet` and write one canonically; `cabac` is §12.4's coding;
  `binding` holds `wsr1/1` and `whm1/1`; `load` runs §10.3 and `encode` the reverse.
  Its corpus is `live-conformance/prior-forms/` (`wai_prior_forms_vectors gen|verify`,
  `tests/prior_wire.rs`, which also loads every corpus prior in every form into the
  integer kernels and compares the native artifact and, for `wsr1/1`, the
  derivation's output).
- Not implemented: the pin verifier (`pin::READABLE_FORMS`) does not read the
  tensor-file forms or NNC, so the reference sink refuses a pin in them with
  `form_unreadable`, and its decoders read native files only; the NNC payload types
  and options §12.1 lists as not read.

The files the reference decoders read from a set (informative). A set built for
another decoder of the capability may name other files; a decode that needs a
file the set lacks is refused with `set_incomplete`.

| capability | shape | files the reference decoder reads from a set |
|---|---|---|
| `wai.neural.int_mlicpp` | one file | `model.wmb` |
| `wai.neural.int_synth` | one file | `int_synth.json` |
| `wai.audio.int_codec` | one file | `model.wam` |
| `wai.splat.int_codec` | one file | `g_s.whm` |
| `wai.neural.int_hyper`, `wai.video.int_hyper` | several | `g_s.whm`, `h_s.whm`, `entropy.json` |
| `wai.neural.encodec32`, `.dac`, `.mimi`, `.wavtokenizer`, `.snac`, `.video_bmshj2018` | one file | `decoder.onnx` |
| `wai.neural.bmshj2018` | several | `decoder.onnx`, `cdfs_q<q>.json` |
| `wai.neural.mbt2018_mean` | several | `hyper_cdfs_q<q>.json`, `hyper_synthesis.onnx`, `gauss_cdfs_q<q>.json`, `synthesis.onnx` |
| `wai.neural.elic` | several | the `mbt2018_mean` files, and `context.onnx` |
| `wai.neural.mlicpp`, `.mlicv2`, `.cmic` | several | the `mbt2018_mean` files, and `entropy.onnx` |
| `wai.neural.glc` | several | `hyper_cdfs_q<q>.json`, `hyper_entropy.onnx`, `context_entropy.onnx`, `synthesis.onnx` |
| `wai.neural.dcvc_rt`, `.dcvc_fm` | several | `hyper_cdfs_q<q>.json`, `hyper_synthesis.onnx`, `gauss_cdfs_q<q>.json`, `temporal_decoder.onnx` |
| `wai.image.jpegai` | several | exact path: `norm.json`, `weights/{hs,hyp,synth}_{y,uv}.json`, `weights/mcm{0..3}_y.json`, `weights/icci.json`. Float path: `hyper_scale_decoder_int_weights.json`, `model_constants.json`, `jpegai_normative_tables.json`, `me-tANS/bounds.csv`, `jpegai_factorized_cdfs.json`, `jpegai_scaler_vec.json`, `jpegai_dequant_consts.json`, `model/CCS_SGMM/tools_0/model_{y,uv}/common_modules/hyper_decoder.onnx`, `model/CCS_SGMM/tools_0/model_y/common_modules/MCM/stage{0..3}.onnx`, `model16/CCS_SGMM/tools_0/model_{y,uv}/synthesis16.onnx`, `e2e/pfchain/icci_{y_m6,uv_m3}.onnx`. A set holding only the exact path's files decodes through that path; where that path refuses (a non-default floating-point environment), the float path needs files the set lacks, and the decode is refused with `set_incomplete` instead of running on unverified files. |
| `wai.generate.spectral` | several (no one-file shape registered); never pinned: its payload names its one model file by SHA-256, and its envelope carries no pin (SPEC §5, *Payload of `wai.generate.spectral`*) | the model file the payload's `model` names (`generate_spectral_model.json` in the conformance vector) |

## 8. Sources

- ISO/IEC 15938-17:2022 and ISO/IEC 15938-17:2024, *Compression of neural
  networks for multimedia content description and analysis*. Read: the public sample
  of the 2022 edition (Introduction, clauses 1–4 and the table of contents),
  which is the source for the scope, the definition of an NNR unit, the number
  conventions, the clause-7 headings (including the integer and raw-float payload
  types) and the patent statement. Not read: clause 7 itself, and the 2024
  edition.
- MPEG, press release of the 154th meeting, *Compressing Tensor Data in AI-based
  Media Coding: MPEG publishes Committee Draft of Amendment of Neural Network
  Coding (NNC)* (mpeg.org, 4 June 2026), and MPEG's meeting list (mpeg.org) for
  the meeting's place and dates: the source for the amendment's stage and
  features, including signing and verification of data units.
- An open implementation that states compliance with ISO/IEC 15938-17:2024: its
  high-level-syntax source reads an `NNR_PT_RAW_FLOAT` payload as raw 32-bit
  floats, and its integer path gives int32 tensors a `skip` approximation with no
  quantisation. Named in the research note.
- ISO/IEC 15938-18:2023 and ISO/IEC 15938-18:2025, *Conformance and reference
  software for compression of neural networks*: the reference software, the
  conformance bitstreams and the decoder and bitstream test procedures. Read: the
  public sample of its draft (DIS, 2022: Introduction, clauses 1–4.3, part of
  4.4, and the table of contents), and the published 2023 edition's catalogue
  abstract. Not read: the
  decoder test procedure (§4.5) and either published edition's full text.
- [research/2030-transport-landscape.md](../research/2030-transport-landscape.md)
  §6.4 (the amendment's contents and stage, the reference software, and the open
  implementation whose licence grants no patent rights), §8 item 9, §9 item 5
  (the signing flag, resolved by the press release).
- The safetensors layout, as published with its reference implementation (format
  description and source, read October 2026; Apache-2.0): the source for §9.1's
  layout, its element types and its 100 000 000-byte header limit.
- GGUF, as published with its reference implementation (the format description,
  read October 2026; MIT): the source for §9.2's layout, its metadata value types,
  its key rule, its alignment default and rule, and the type numbers of §9.2's table.
- An open implementation of ISO/IEC 15938-17 that states compliance with the 2024
  edition (its high-level syntax and its arithmetic coder, read October 2026, under a
  BSD licence that grants no patent rights): the source for §12's syntax and for
  Appendix A's procedure and tables. Named in the research note above.

## 9. Tensor files: `wai.prior.safetensors` and `wai.prior.gguf`

A parameter set that is one artifact of named tensors MAY be pinned as one tensor file.
Its pin's `sha256` is the SHA-256 of the whole file (§11). Two layouts are registered,
each read as this section states; a reader refuses a file that breaks a rule with the
code of §13 named at the rule, and the first rule broken, in the order given, is the
one reported.

### 9.1 safetensors

1. The first 8 bytes are `N`, an unsigned 64-bit little-endian integer. A file shorter
   than 8 bytes is `header_truncated`.
2. `N` past 100 000 000 is `header_too_large`; `8 + N` past the end of the file is
   `header_truncated`.
3. The next `N` bytes are a JSON text (RFC 8259, UTF-8) whose value is an object, with
   no member named twice in any object and at most 64 levels of nesting
   (`header_malformed`). Whitespace around the value is admitted: the layout pads its
   header with spaces.
4. The member `__metadata__`, where present, is an object whose every value is a string
   (`header_malformed`).
5. Every other member is a tensor, named by the member's name. Checked in this order:
   the name is not empty; the value is an object of exactly the members `dtype`,
   `shape` and `data_offsets`; `dtype` is a string (each `tensor_malformed`); `dtype` is
   in the table below (`dtype_unknown`); `shape` is a list of integers; `data_offsets` is
   a list of two integers `[begin, end]` with `begin` at most `end` (each
   `tensor_malformed`). An integer here is written in plain decimal (no sign, fraction,
   exponent or leading zero) and is at most 2^64 − 1.
6. A tensor's element count is the product of its `shape` (1 for an empty `shape`); a
   count, or a size in bytes, past 2^64 − 1 is `tensor_malformed`. `end − begin` is that
   count times the element's size (`offset_mismatch`).
7. Offsets count from the byte after the header. Ordered by `begin`, the tensors cover
   those bytes exactly: the first begins at 0, each begins where the one before ends,
   and the last ends at the end of the file (`offset_mismatch`).

Steps 4 to 6 apply to the header's members in the order it writes them, and step 7 once
they all pass.

A tensor's bytes are its elements in row-major order (the outermost dimension first),
each little-endian.

| `dtype` | element | bytes |
|---|---|---|
| `BOOL` | boolean | 1 |
| `U8`, `I8` | unsigned, signed integer | 1 |
| `U16`, `I16` | unsigned, signed integer | 2 |
| `F16`, `BF16` | binary16, the 16-bit truncation of binary32 | 2 |
| `U32`, `I32` | unsigned, signed integer | 4 |
| `F32` | binary32 | 4 |
| `U64`, `I64` | unsigned, signed integer | 8 |
| `F64` | binary64 | 8 |
| `F8_E5M2`, `F8_E4M3` | 8-bit floating point | 1 |

### 9.2 GGUF

Version 3, little-endian. Every integer below is little-endian; a field due past the end
of the file is `header_truncated`.

1. Bytes 0 to 3 are `GGUF` (`bad_magic`; a file shorter than 4 bytes is
   `header_truncated`).
2. `version`, a u32, is 3 (`version_unsupported`). The big-endian variant of version 3
   reads here as another number and is refused the same way.
3. `tensor_count` and `metadata_kv_count`, each a u64. A count whose least size (12
   bytes a pair, 28 a tensor description) is past the file's length is
   `header_truncated`, before anything is reserved for it.
4. A string is a u64 length and that many bytes, UTF-8 (`header_malformed`).
5. Each key-value pair: the key, a string of `.`-separated non-empty segments of `a` to
   `z`, `0` to `9` and `_`, at most 65 535 bytes, no key twice (`header_malformed`);
   the value type, a u32 from 0 to 12 (`header_malformed`); the value. A boolean (type
   7) is 0 or 1 (`header_malformed`). An array (type 9) is an element type, a u64
   count and the elements; this reader reads one level of array, so an element type of
   9 is `header_malformed` (checked before the count), and a count whose least size is
   past the bytes left is `header_truncated`.
   `general.alignment`, where present, is a u32 (type 4), non-zero and a multiple of 8
   (`header_malformed`); without it the alignment is 32.
6. Each tensor description: the name, 1 to 64 bytes, no name twice
   (`tensor_malformed`); `n_dimensions`, a u32 from 1 to 4, and that many dimensions,
   u64 each, innermost first, none 0 (`tensor_malformed`); the type, a u32 from the
   table below (`dtype_unknown`); the offset, a u64, a multiple of the alignment
   (`offset_mismatch`). A `Q8_0` tensor's innermost dimension is a multiple of 32, and
   an element count or a size in bytes past 2^64 − 1 is malformed (`tensor_malformed`).
7. The tensor data begins at the first multiple of the alignment at or after the end of
   the descriptions; the bytes between are zero (`header_malformed`), and the file
   ending before the data begins is `header_truncated`. A tensor's bytes are at its
   offset from there; no two tensors overlap and none runs past the end of the file
   (`offset_mismatch`).

A tensor's shape, as §10 and §11 use it, is its GGUF dimensions in reverse order
(outermost first); its bytes are its elements in that row-major order.

| type | number | element | bytes |
|---|---|---|---|
| `F32` | 0 | binary32 | 4 |
| `F16` | 1 | binary16 | 2 |
| `Q8_0` | 8 | blocks of 32 elements: a binary16 scale and 32 signed bytes | 34 per block |
| `I8` | 24 | signed integer | 1 |
| `I16` | 25 | signed integer | 2 |
| `I32` | 26 | signed integer | 4 |
| `I64` | 27 | signed integer | 8 |
| `F64` | 28 | binary64 | 8 |
| `BF16` | 30 | the 16-bit truncation of binary32 | 2 |

GGUF defines further types, which this reader refuses (`dtype_unknown`): their sizes
are not stated here. The file's string values are its metadata; a value of another type
is read and checked and not kept, so a file that holds one is not canonical (§11.2).

### 9.3 What a reader obtains

The metadata, a map from strings to strings, and the tensors, each a name, an element
type, a shape and bytes, in ascending byte order of their names. Two readers that follow
this section obtain the same tensors from the same file: no rule leaves a choice, since a
name twice and overlapping or uncovered bytes are refused. That is why the registry
lists both forms as established exact (§5): reading hands the decoder the bytes, and
what the decoder makes of a floating-point tensor is its own determinism contract.

## 10. The integer-quantised profile `wai-int/1`

A prior is in the profile when it is a tensor file, in a form of §9 or the NNC form of
§12, whose every tensor is a signed integer the kernel reads as it is. No scale is
applied on load; any scale the kernel uses (a multiplier, a shift) is itself an integer
tensor; nothing is floating point. The profile is how a network trained in floating
point reaches an integer kernel: whoever quantises it makes the integers once (the
integer decoders' priors round half to even at a fixed scale), and every sink then reads
the same integers, with no rounding on load.

### 10.1 Metadata and element types

| form | the metadata, exactly |
|---|---|
| safetensors, NNC | `wai.binding`: a binding of §10.2; `wai.profile`: `wai-int/1` |
| GGUF | the same, and `general.architecture`: `wai`, a key the GGUF layout requires |

In NNC the metadata travels in the topology unit (§12.3). The element types are `I8`,
`I16`, `I32` and `I64` (GGUF types 24 to 27), little-endian two's complement. NNC
carries every integer tensor as `I32` (§12.1), and the binding's type then bounds its
values.

### 10.2 Bindings

A binding maps a native artifact, byte for byte, to named integer tensors and back.

**`wsr1/1`**: the `WSR1` prior of [exact-upscale](exact-upscale.md) §3.1, with layers
`0` to `n − 1`, `n` from 1 to 8, `<i>` written in plain decimal:

| tensor | type | shape | values |
|---|---|---|---|
| `act_hi` | `I16` | [1] | 1 to 32767 |
| `layer.<i>.weight` | `I8` | [cout, cin, k, k] | any |
| `layer.<i>.bias` | `I32` | [cout] | any |
| `layer.<i>.mult` | `I32` | [cout] | 1 to 65535 |
| `layer.<i>.shift` | `I8` | [1] | 0 to 31 |

`cin` is 3 in layer 0 and the previous layer's `cout` after it; `k` is 1, 3 or 5; `cout`
is 1 to 64, and 12 in the last layer. The native bytes are written as exact-upscale §3.1
lays them out from these values. A native artifact that does not read under that section
is `native_malformed`.

**`whm1/1`**: the `WHM1` model of [integer-payloads](integer-payloads.md) §9 (the magic,
`afrac`, `gf`, `shift`, the layer count, then each layer by its tag), with layers `000`
to `n − 1` written in three digits, `n` at most 1000:

| tensor | type | shape | values |
|---|---|---|---|
| `header` | `I64` | [3] | `afrac`, `gf`, `shift`: each 0 to 2^32 − 1 |
| `layer.NNN.conv` (tag 1) | `I64` | [5] | in, out, k: each 1 to 2^32 − 1; stride, pad: each 0 to 2^32 − 1 |
| `layer.NNN.convt` (tag 0) | `I64` | [6] | in, out, k as for `conv`; stride, pad, opad: each 0 to 2^32 − 1 |
| `layer.NNN.weight` | `I16` | `conv`: [out, in, k, k]; `convt`: [in, out, k, k] | any |
| `layer.NNN.mult`, `layer.NNN.bias` | `I64` | [out] | any |
| `layer.NNN.igdn` (tag 2) | `I64` | [1] | c: 1 to 2^32 − 1 |
| `layer.NNN.gamma` | `I32` | [c, c] | any |
| `layer.NNN.beta` | `I64` | [c] | any |
| `layer.NNN.relu` (tag 3) | `I8` | [1] | 0 |
| `layer.NNN.leaky` (tag 4) | `I64` | [2] | `slope_q`: any; `slope_frac`: 0 to 2^32 − 1 |

A layer is the kind its one kind tensor (`conv`, `convt`, `igdn`, `relu` or `leaky`)
names, with the tensors listed under that kind. A `WHM1` layer with a dimension of 0 has
no tensor form (`binding_mismatch`), and more than 1000 layers neither; a native artifact
that does not read as integer-payloads §9 lays it out is `native_malformed`.

### 10.3 Loading and encoding

A sink loads a tensor file of the profile in these steps, refusing at the first that
fails:

1. Read the file in its form (§9, §12), with the form's codes.
2. Require the file canonical (§11): `header_not_canonical`.
3. Require §10.1's metadata exactly, `wai.profile` being `wai-int/1`
   (`profile_absent`); the binding registered (`binding_unknown`); every tensor of a
   profile integer type, `I32` in NNC (`dtype_not_integer`).
4. The binding's structure, then its names. For `wsr1/1`: `n` is the number of
   `layer.<i>.weight` tensors (`<i>` in plain decimal); the indices are `0` to `n − 1`
   with `n` from 1 to 8, and each weight's first and last dimensions give a `cout` and a
   `k` the table admits (`binding_mismatch`). For `whm1/1`: each layer index (three
   digits) has exactly one kind tensor and the indices are `000` to `n − 1`
   (`binding_mismatch`); then, layer by layer, its kind tensor (but `relu`'s) has the
   type and shape the table gives (`binding_mismatch`), and its in, out and k (`conv`,
   `convt`) or c (`igdn`) are from 1 to 2^32 − 1 (`value_out_of_range`). Then the
   tensors are exactly the names the binding gives for those layers (`binding_mismatch`),
   and then each, in the order of step 5, has the type and shape it gives
   (`binding_mismatch`).
5. Every value within its type and the binding's range (`value_out_of_range`), tensor by
   tensor in this order: for `wsr1/1`, `act_hi`, then layer by layer its `weight`,
   `bias`, `mult` and `shift`; for `whm1/1`, `header`, then layer by layer its kind
   tensor and, for `conv` and `convt`, `weight`, `mult`, `bias`, for `igdn`, `gamma`,
   `beta`.
6. Write the native artifact from the values.

The kernel reads the native artifact's bytes through the capability's own reader. A
prior loaded this way is the native artifact, byte for byte, so it decodes as the native
artifact decodes. Encoding is the reverse: read the native artifact into tensors, add
§10.1's metadata, and write the file canonically (§11).

## 11. The digest rule

A pin in a tensor-file form covers the whole file: the tensors' bytes and the canonical
header that names them. The forms are canonical as stated below, and a sink refuses a
file that is not (§10.3 step 2). So, in the profile, a file is a function of its tensors
(their names, types, shapes and bytes) and its metadata, and one prior has exactly one
file in each form: the digest identifies the tensors, and the tensors the digest. One
prior in three forms has three digests; a pin names one, and §2 forbids resolving it
with another.

### 11.1 safetensors

The header is `{`, then `"__metadata__":{` with the metadata's members in ascending byte
order of their names and `}` (omitted when there is no metadata), then the tensors in
ascending byte order of their names, each `"<name>":{"dtype":"<dtype>","shape":[<d>,…],
"data_offsets":[<begin>,<end>]}`, every two members separated by `,`, then `}`: no
whitespace, strings escaped as RFC 8785 §3.2.2.2 escapes them, integers in plain
decimal. Then `0x20` bytes until `8 + N` is a multiple of 8. The tensors' bytes follow in
the same order, contiguous from offset 0.

### 11.2 GGUF

Version 3. The metadata pairs are string values (type 8), in ascending byte order of
their keys, with no `general.alignment` (the alignment is 32). The tensor descriptions
are in ascending byte order of their names. The first tensor is at offset 0, and each
later one at the first multiple of 32 after the end of the one before; the bytes
between the header and the data, and between tensors, are zero; nothing follows the last
tensor.

### 11.3 NNC

The bitstream §12.3 writes.

## 12. The NNC reader and writer

### 12.1 What was read, the subset, and where it stops

Readable: the public sample of the 2022 edition (its scope, the definition of an NNR
unit, its number conventions and its clause titles) and an open implementation that
states compliance with the 2024 edition (§8): its high-level syntax and its arithmetic
coder. The syntax of §12.2 is the syntax that implementation reads and writes, and
Appendix A is its arithmetic coding. The standard's syntax, decoding and entropy-coding
clauses were not read, so nothing here states a field's semantics beyond what that
implementation does with it. The reader and writer were measured against that
implementation (§12.4), not against the conformance bitstreams of ISO/IEC 15938-18.

The subset: one `NNR_STR`, first; one `NNR_MPS`, before any data unit, with no
performance map and topology elements referenced by name; at most one `NNR_TPL`, after
the MPS, of a storage format that carries its topology as a string (0, 3 or 4) with raw
compression; one `NNR_NDU` per tensor, each carrying one topology element by name, its
input parameters and dimensions in band, and a payload of one of two types:

- `NNR_PT_INT` (0): integers, with `dq_flag` 0, `scan_order` 0 and the unary length in
  band, coded as Appendix A codes them; read back as `I32`.
- `NNR_PT_RAW_FLOAT` (2): 32-bit floats, little-endian, as they are; read back as
  `F32`.

Everything else is refused with `nnc_not_read`, naming what was met: the units
`NNR_LPS`, `NNR_QNT` and `NNR_AGG`; a partial data counter; a performance map; topology
elements referenced by index; another topology storage format or a compressed topology;
the payload types `NNR_PT_FLOAT` (quantised parameters) and `NNR_PT_BLOCK`; several
topology elements in one unit; a decompressed data format other than the payload's
own; input parameters, dimensions or the unary length out of band; compressed parameter
types other than 0; `dq_flag` 1 (dependent quantisation); a `scan_order` other than 0
(block scans with entry points); a tensor of more than 2^28 elements.

**Where it stops, and why.** A quantised payload reconstructs each parameter from a
quantisation index and a step size, and that arithmetic, with whatever tolerance
conformance allows it, is in the text that was not read; dependent quantisation and
block scans add a state machine and entry points an integer prior does not need. Within
the subset, decoding is integer arithmetic on fixed widths from the first bit to the
last (Appendix A), so the integers a reader obtains are a function of the bits, and a
prior in the profile round-trips exactly (§14).

### 12.2 Reading

Bits are read most significant first: u(n) is an n-bit unsigned integer, i(n) an n-bit
two's complement integer, ue(k) the order-k exponential-Golomb code (zero bits, each
adding 2^k to the value and raising k by one, until a one bit, then k more bits added to
the value), and a string a zero-terminated UTF-8 byte sequence that begins on a byte
(`nnc_malformed` otherwise). A byte alignment is a 1 bit, then 0 bits to the byte
boundary (`nnc_malformed`).

Units are read in order until the bitstream ends; an empty bitstream is
`nnc_truncated`. Each unit: `nnr_unit_size_flag` u(1), then `nnr_unit_size`, u(15) or,
with the flag, u(31), counting the whole unit, its size field included (a unit under 3
bytes or past the end of the bitstream: `nnc_truncated`); `nnr_unit_type` u(6);
`independently_decodable_flag` u(1); `partial_data_counter_present_flag` u(1). The first
unit is `NNR_STR` (`nnc_malformed`), and a partial data counter is not read
(`nnc_not_read`), in that order. A field that runs past its unit's end, and a string
with no zero byte before it, are `nnc_truncated`; an exponential-Golomb code longer than
40 bits is `nnc_malformed`. Then by type, fields in this order, each check where its
field is read:

- `NNR_STR` (0): only the first unit (`nnc_malformed`); `general_profile_idc` u(8).
- `NNR_MPS` (1), once and before any data unit (`nnc_malformed`):
  `topology_carriage_flag`, four performance-map flags, `mps_quantization_method_flags`
  u(3), `mps_topology_indexed_reference_flag`, seven reserved bits; the reserved bits
  are zero (`nnc_malformed`), then the performance-map flags are zero and then the
  indexed-reference flag is (each `nnc_not_read`); with quantisation flags,
  `mps_qp_density` u(3) and `mps_quantization_parameter` i(13); a byte alignment.
- `NNR_TPL` (3), once and after the MPS (`nnc_malformed`): `topology_storage_format`
  u(8), `topology_compression_format` u(8), the topology as a string. In storage format
  0, a topology that is a JSON object of string values is the file's metadata (§10.1).
- `NNR_NDU` (5), after the MPS (`nnc_malformed`): `nnr_compressed_data_unit_payload_type`
  u(5), `nnr_multiple_topology_elements_present_flag` u(1),
  `nnr_decompressed_data_format_present_flag` u(1), `input_parameters_present_flag`
  u(1), after which the payload type is 0 or 2 and then the multiple-elements flag is 0
  (each `nnc_not_read`); the topology element's name, a string, not empty
  (`nnc_malformed`); for `NNR_PT_INT`, `dq_flag` u(1), 0 (`nnc_not_read`);
  `nnr_decompressed_data_format` u(7) where present, 0 for `NNR_PT_INT` and 1 for
  `NNR_PT_RAW_FLOAT` (`nnc_not_read`); the input parameters are in band
  (`nnc_not_read`); `tensor_dimensions_flag` u(1), `cabac_unary_length_flag` u(1),
  `compressed_parameter_types` u(4), which is 0, and then the dimensions are in band
  (each `nnc_not_read`); the dimension count ue(1), from 1 to 16, and each dimension
  ue(7), outermost first, whose product is from 1 to 2^64 − 1 (each `nnc_malformed`) and
  at most 2^28 (`nnc_not_read`); `cabac_unary_length_minus1` u(8) where flagged; with
  more than one dimension, `scan_order` u(4), 0 (`nnc_not_read`); a byte alignment; then
  the payload, to the unit's end. An integer payload with the unary length out of band is
  `nnc_not_read`.

A unit other than a data unit ends exactly where its fields end, and a data unit's
payload fills the rest of it: four bytes per element of raw floats, and an integer
payload whose decoding (Appendix A) ends exactly at the unit's end (`nnc_malformed`).
Two data units carrying one name are `nnc_malformed`, checked once every unit has been
read.

### 12.3 Writing

`NNR_STR` with profile 0. `NNR_MPS` with `topology_carriage_flag` 1 when there is
metadata and every other field 0. With metadata, `NNR_TPL` of storage format 0 and
compression 0, its topology the metadata as a JSON object, keys in ascending byte order,
no whitespace, strings escaped as RFC 8785 §3.2.2.2 escapes them. Then one data unit per
tensor, in ascending byte order of names: an integer tensor as `NNR_PT_INT`, a binary32
tensor as `NNR_PT_RAW_FLOAT`; `independently_decodable_flag` 1, no partial data counter,
one topology element, no decompressed data format, input parameters in band with both
flags 1, `compressed_parameter_types` 0, `cabac_unary_length_minus1` 10, `scan_order` 0
where present, `dq_flag` 0. Each unit takes the 15-bit size when the whole unit is under
32 768 bytes, else the 31-bit size. An integer past ±(2^31 − 1) has no `NNR_PT_INT` form
(`value_out_of_range`).

### 12.4 Measured against an open implementation

On 2026-10-22 the subset was measured against the open implementation of §12.1 (source
at commit `0e3dcd2961701572d253f175754c09952a4b44c7`, its arithmetic coder compiled from
that source; arm64): for each of the seven priors of the corpus (§14), that
implementation's decoder read the NNC file this extension's writer made to the integers
the prior holds; its encoder, given those integers (one topology element per data unit,
`dq_flag` 0, `scan_order` 0, unary length 10, no parameter optimisation), wrote every
data unit byte-identical to this writer's; and this reader read that encoder's whole
bitstream to the same integers. Its bitstream differs from this writer's only in the
topology unit, which carries §10.1's metadata here. The check is
[`tools/nnc_interop_check.py`](../tools/nnc_interop_check.py); it runs the other
implementation's code, so it is a measurement this repository records, not a CI step.

## 13. Refusals

| code | where |
|---|---|
| `header_truncated` | §9.1 steps 1 and 2; §9.2: a field, a count or the data's start past the end |
| `header_too_large` | §9.1 step 2 |
| `header_malformed` | §9.1 steps 3 and 4; §9.2 steps 4, 5 and 7 |
| `bad_magic` | §9.2 step 1 |
| `version_unsupported` | §9.2 step 2 |
| `tensor_malformed` | §9.1 steps 5 and 6; §9.2 step 6 |
| `dtype_unknown` | §9.1 step 5; §9.2 step 6; a tensor of a type a writer's form has no name for |
| `offset_mismatch` | §9.1 steps 6 and 7; §9.2 steps 6 and 7 |
| `header_not_canonical` | §10.3 step 2: the file reads and is not its canonical form (§11) |
| `nnc_truncated` | §12.2: a unit past the end; an integer payload that ends inside its unit (Appendix A) |
| `nnc_malformed` | §12.2, Appendix A |
| `nnc_not_read` | §12.1: outside the subset, with what was met |
| `profile_absent` | §10.3 step 3 |
| `binding_unknown` | §10.3 step 3 |
| `dtype_not_integer` | §10.3 step 3 |
| `binding_mismatch` | §10.3 step 4; §10.2: a native artifact with no tensor form |
| `value_out_of_range` | §10.3 steps 4 and 5; §12.3: an integer NNC cannot carry |
| `native_malformed` | §10.2: a native artifact that does not read under its own format |

## 14. Conformance corpus

[`live-conformance/prior-forms/`](../live-conformance/prior-forms/) holds, for seven
native artifacts other corpora commit, each pinned by SHA-256 (two trained `WSR1`
priors and a seeded one of the exact-upscale corpus, four generated `WHM1` models of the
integer-operators corpus), the canonical file in each of the three forms; native
artifacts that do not read or that NNC cannot carry; and negative controls, each refused
with its code. A vector is an *encode* (a native artifact to a file, or a refusal) or a
*load* (§10.3 over a file: the binding and the native artifact, or a refusal), and a
verifier conforms when it reaches every vector's outcome, its file bytes and its native
bytes. `wai_prior_forms_vectors gen|verify` writes and checks it, `tests/prior_wire.rs`
regenerates it and loads every prior in every form into the integer kernels, and
`live-conformance/prior_forms_verify.py`, written from this text and sharing no code
with `wai-rs`, is its second implementation.

## 15. Where a set is fetched

A pin names a set by its digest and says nothing of where the set is (SPEC §3.1). Over HTTP
a set is served at `<root><sha256>` below a **set root**, an origin's own being
`/.well-known/wai-sets/`, and a sink that lacks a set asks, in order, the roots of its own
configuration, the location hints that a MoQ catalog's `wai_priors` entry or a WAI
multivariant playlist states, and the origin's well-known root
([http-delivery](http-delivery.md) §8.5, §8.7). Any server may serve a set. Whatever served
the bytes, a sink holds them only when their digest is the pin's, and then under SPEC §3.1's
checks like any other set; a server that serves other bytes under the set's name is passed
over for the next root. So a mirror, a cache, a peer or a node of the sink's household that
holds a set serves it as well as the origin does, and no central server is on the path.

The pin carries no location. A location in a pin would be signed into every envelope that
carries it and outlive the server it names; a hint beside the pin can change without
touching an envelope, and is never evidence.

A file of a `wai.prior.set` is a resource of its own under its own digest, so a sink that
holds a set's predecessor fetches only the files the two do not share (SPEC §3.1,
*Updates*).

**Reference implementation and corpus.** `prior_carriage` (feature `prior_carriage`) is the
reference implementation, `prior_carriage::locations` for this section. The corpus
[`live-conformance/prior-carriage/`](../live-conformance/prior-carriage/) holds, for this
section, hints read from catalog entries and playlists, and fetches over the responses each
case states: a set held from the second root its hint lists after the first served other
bytes, a root that does not answer and one that answers with a content coding, a set past a
sink's bound, a listing and its files held from two roots, a file no root holds, and a pin
with a member that names a location, which no fetch reads. `wai_prior_carriage_vectors
gen|verify` writes and checks it, `tests/prior_carriage.rs` requires it to regenerate byte
for byte, and `live-conformance/prior_carriage_verify.py`, written from this text and
http-delivery's and sharing no code with `wai-rs`, is its second implementation.

## 16. A successor coded against its predecessor

A re-tuned set is a new set under a new digest (SPEC §3.1, *Updates*), and most of its bytes
are often its predecessor's. RFC 9842 (*Compression Dictionary Transport*) lets an HTTP stack
send a response coded against a dictionary the client already holds, named by its SHA-256 in
`Available-Dictionary`. A set's digest in a one-file form is the SHA-256 of that one file, so a
held set is a dictionary under the very name its pin gives it, with nothing to map: a sink that
holds a predecessor names it, a server that holds both answers with the successor coded
against it (`dcz` or `dcb`), and the sink decodes the response and holds the successor only
when the decoded bytes' SHA-256 is the successor's pin ([http-delivery](http-delivery.md)
§8.8). A server that codes nothing, or codes against the wrong set, costs bytes and never
correctness.

- **The coded bytes are a transfer.** No pin names them, and no form is registered for them,
  as none is for an NNC incremental update (§2): what a sink holds, and what a pin covers, is
  the self-contained successor the decoding yields. A delta that would need a third set to
  decode cannot arise: the dictionary is the one set the request named, checked by the digest
  the coded body repeats.
- **A set of several files** is coded file by file. Each file of a `wai.prior.set` is served
  under its own digest, so a client MAY name, for a file of the successor, the file at the same
  path in its predecessor's listing; a file the two share is not fetched at all (§15).
- **Which set is named.** A client that writes the field itself names the set the successor's
  pin `supersedes`, when it holds it. A client whose HTTP stack keeps dictionaries itself names
  what that stack chooses; the result is checked the same way.
- **Privacy.** Naming a held set tells the server that the sink holds it, as the Sink
  Capability Descriptor's `held_sets` does. http-delivery §12.5 and RFC 9842 §10 say what that
  discloses and what a sink may name.

**Reference implementation and corpus.** `prior_carriage::dictionary`; it decodes `dcz` only.
The corpus holds `title`, the upscale corpus's per-title `WSR1` prior, which was fine-tuned
from its generic prior `generic`, coded against `generic` (`files/title-from-generic.dcz`), and
the fetches of
http-delivery §8.8 over it: the successor held through its predecessor; a coded response no
dictionary was named for, and one in a coding the sink did not list; a header naming another
dictionary, a body that is not a `dcz` header, a frame whose window passes RFC 9842's limit
(`files/title-window-16m.dcz`), a truncated frame, each followed by the same root asked without
a dictionary; a decoding that yields another set; and one past the sink's bound. Its `stock`
entry states the check a stock Zstandard tool makes: the body after its 40-byte header, decoded
against `generic`, has `title`'s SHA-256.

## 17. Amortisation, bootstrap and generations

A set costs bytes before it saves any: a sink fetches it once and then decodes the titles
pinned to it in fewer bytes than their classical renditions take. This section states when
that is worth it, charged to each sink, and how a publisher re-tunes a set without stranding
the titles coded against the one before.

### 17.1 Terms

- A **generation** is a set and the titles an origin codes against it.
- A **catalog epoch** is the period in which an origin codes new titles against one
  generation. An origin freezes a set for its epoch: every title it codes in the epoch pins
  that set, and a re-tuned set begins the next epoch, as a new generation whose pin
  **SHOULD** name the previous epoch's set in `supersedes` (SPEC §3.1).
- A title's **saving** to a sink is the bytes of the rendition the sink fetches when it does
  not decode against the set (the classical rendition, at the quality the origin delivers),
  less the bytes of the pinned rendition and of the records that name the set and that the
  sink fetches with it ([exact-upscale](exact-upscale.md) §4's upscale records among them).
  Both are in the heads the sink fetches: a `WAI2` rendition table states every component's
  length (SPEC §7.1).
- A generation's **cost** to a sink is 0 when the sink holds its set; the coded bytes of §16
  when the sink holds the set this one is coded against and the origin offers that coding;
  and the set's bytes otherwise (for a `wai.prior.set`, its listing and every file the sink
  does not hold).
- The **span** is the period over which a sink's fetches are counted, from one instant to a
  later one. Whoever applies this section states the span with the outcome, and two outcomes
  over different spans are not compared.
- The **cap** is the most generations the origin plans a sink to hold at once, at least 1.

### 17.2 The rule, charged per sink

For one sink, and the titles it is expected to fetch within the span, each with the number of
times it is fetched:

1. A generation's **saving** is the sum, over its titles the sink fetches whose saving is
   above 0, of the number of fetches times the saving. A title whose saving is 0 or less takes
   its classical rendition whatever the sink holds.
2. Its **net** is its saving less its cost to that sink. It is **worth holding** when the net
   is above 0: the bytes the set saves must exceed what holding it costs.
3. The sink holds the generations worth holding, at most the cap, the largest net first and,
   at an equal net, the later generation first. When fewer than the cap are kept, it keeps
   the generations it already holds, the later first, until the cap is reached; any other it
   holds may be evicted. Costs are those at the time the rule is applied, so a successor
   coded against a predecessor this step evicts is fetched before the predecessor goes.
4. A title is decoded against its set when its generation is kept and its saving is above 0,
   and takes its classical rendition otherwise.

The cost is charged per sink. A set's bytes are counted in full for every sink that fetches
it, never divided among the sinks a publisher serves: every one of them fetches the whole set.
So a set that saves each of a thousand sinks less than its own size is not worth sending to
any of them, however much the thousand save together.

**An origin SHOULD** encode a title's pinned rendition, and list its set for sinks to fetch
(§15), only where the set's generation is kept for the sinks the content reaches by the
origin's own estimate of their fetches; **a sink SHOULD** fetch a set only where its
generation is kept over the fetches the sink expects.

### 17.3 Bootstrap

- **First contact.** A sink that has disclosed no held set counts as one that holds none:
  every cost is the set's bytes. The Sink Capability Descriptor's `held_sets` is how a sink
  says what it holds, and it is sent only under http-delivery §12.5's rules: off unless turned
  on for the site, and then only what the site's content pins.
- **The classical rendition.** An encoder whose content reaches sinks it does not control
  carries a classical rendition beside each pinned one (SPEC §4), so a sink for which a set is
  not worth holding takes the classical rendition and fetches nothing.
- **Fetching.** A sink for which a generation is kept fetches its set as §15 states, before it
  decodes a title pinned to it, and holds it under SPEC §3.1.

### 17.4 Generations

Older titles keep the digests they were coded against, so a re-tuned set leaves the back
catalog pinned to the generations before it. An origin either keeps serving those titles,
which a sink then decodes against their own generation where step 3 keeps it and classically
otherwise, or re-encodes a title against a later set: a new envelope with a new pin, while
the old envelope still decodes wherever its set is held. Freezing a set per epoch bounds the
generations a back catalog spans, the cap bounds the generations a sink holds, and §16 makes
a successor cost a sink only the coded bytes when the sink holds its predecessor.

**Reference implementation and corpus.** `prior_carriage::amortise::plan` applies §17.2 to a
stated plan: a span, a cap, the generations in epoch order (each with its set's bytes and,
where it is coded against an earlier one, that generation and the coded bytes), the titles
(each with its generation and its pinned and classical bytes) and one or more sinks (each with
the generations it holds and its fetches per title). For each sink it gives each generation's
saving, cost and net, the generations kept, fetched and evicted, each title's rendition, and
the bytes the sink receives beside the bytes it would receive with no set. The corpus's
worked plans: a set worth holding and one that is not; a net of exactly 0, which is not worth
holding; a held set, which costs nothing; a title whose pinned rendition is larger; a
successor costing its coded bytes where its predecessor is held and its whole set where it is
not; a sink holding two generations when a third is worth fetching, with a cap of two, which
evicts the one with the smallest net, and with a cap of three; an equal net, where the later
generation is kept; and three sinks that would together save more than the set's size and
each save less, none of which fetches it. Plans that do not read are refused
(`plan_malformed`).

## 18. Usage, access and leakage

A set fitted to a catalog's frames is the rights holder's as much as the frames are. This
section states the terms that travel with a set, a form that keeps a set's bytes unreadable to
any sink its origin has not released a key to, and what a set can disclose of the frames it
was fitted to.

### 18.1 The usage statement

A **usage statement** is a JSON object with exactly these members, read from JSON text in which
no object names a member twice, at most 65 536 bytes long:

| member | value |
|---|---|
| `kind` | `"wai-set-usage"` |
| `licence` | the licence the set's bytes are under, as an SPDX licence expression (*SPDX Specification* 2.3, Annex D), or `null` where the statement names none |
| `terms` | an `https` URI of the terms under which the set may be held and decoded, 8 to 2048 bytes of `!` to `~`, or `null` |
| `content_derived` | `true` when the set's parameters were fitted to frames of content (a per-title or a per-catalog prior), `false` otherwise |
| `redistribute` | `true` when a holder may serve the set to others, `false` when only its origin, and caches that serve for the origin, may |
| `ai_usage` | an [ai-usage](ai-usage.md) §3 statement, read as ai-usage §3.6 reads one, governing uses of the set's bytes other than decoding the content pinned to it (training on them, extracting from them), or `null` |

A licence expression is read by the grammar of SPDX 2.3 Annex D: simple expressions (a licence
identifier, with `+` or not, or `LicenseRef-` and an identifier string, with `DocumentRef-`, an
identifier string and `:` before it or not), each with `WITH` and an exception identifier or
not, joined by `AND` and `OR` and grouped by parentheses; the operators upper case; tokens
separated by single spaces; at most 1024 bytes. An identifier is checked for its characters
(letters, digits, `-` and `.`), and is not looked up in the SPDX licence list. A statement that
breaks a rule of this section is refused (`set_usage_malformed`), and so is one whose
`ai_usage` ai-usage refuses.

- **Where it is bound.** A statement is bound to a set only as part of the bytes the set's pin
  covers: in a `wai.prior.set`, as the file of the top-level path `wai-usage.json` of its
  listing, listed like any other file; in a `wai.prior.sealed`, in its header (§18.2). A file
  of that name at any other path of a listing is a file of the set and no statement, and a
  statement found anywhere else (served beside a set, stated in a catalog, quoted in a
  playlist) governs nothing. Since the pin covers it, a statement cannot be dropped or changed
  without the set failing its pin.
- **A bound statement that does not read.** A sink that holds a listing and every file it names
  (SPEC §3.1) reads the file of the path `wai-usage.json`, where the listing has one, as a
  statement. One that breaks a rule of this section leaves the set not held
  (`set_usage_malformed`), as §18.2 step 3 does for a sealed set: a sink holds a set with the
  terms bound to it, or does not hold it.
- **Redistribution.** A holder of a set whose bound statement says `redistribute: false`
  **MUST NOT** serve it to any other party, nor name a root of its own for it in a hint (§15),
  other than as an HTTP cache that stores and serves it for its origin under
  [http-delivery](http-delivery.md) §9.
- **No statement.** A set with no bound statement states no terms: nothing in this extension
  grants or withholds a use of it.
- **What a statement is not.** A statement says what the rights holder permits. It keeps the set
  from no one: §18.2 does that.

### 18.2 Sealed sets: `wai.prior.sealed`

A **sealed set** is a set in a one-file form encrypted under a 16-byte AES-128 key that its
origin releases to the sinks it entitles. Its pin names the sealed bytes, so a mirror, a cache
or a peer that holds them serves them as it serves any set (§15), and a sink checks them by
digest before it has a key. All integers are little-endian.

| offset | size | field |
|---|---|---|
| 0 | 4 | magic `WSK1` |
| 4 | 1 | `k`, the inner form's length, 0 to 64 |
| 5 | `k` | the inner form, bytes `!` to `~`: empty for a capability's one file (a form-less pin), or `wai.prior.safetensors` or `wai.prior.gguf` |
| 5 + `k` | 16 | `kid`, the key's identifier |
| 21 + `k` | 16 | `iv`, the initial counter block |
| 37 + `k` | 32 | `inner`, the SHA-256 of the plaintext: the set's digest in its inner form |
| 69 + `k` | 4 | `u`, the usage statement's length, 0 to 65 536 |
| 73 + `k` | `u` | the usage statement (§18.1), or nothing |
| 73 + `k` + `u` | 8 | `L`, the plaintext's length, 1 to 2^40 |
| 81 + `k` + `u` | `L` | the ciphertext |

The file is exactly `81 + k + u + L` bytes. The ciphertext is the plaintext under AES-128
(FIPS 197) in counter mode (NIST SP 800-38A §6.5), the counter block starting at `iv` and
incremented as one 128-bit big-endian integer for each 16-byte block; decryption is the same
operation.

A sink reads a sealed set in this order, the first check that fails being the reason:

1. the layout above (`sealed_malformed`);
2. the inner form, which is admitted (`sealed_inner_form`): none, `wai.prior.safetensors` or
   `wai.prior.gguf`, as the table above lists, and no other string;
3. the usage statement, where `u` is not 0 (`set_usage_malformed`);
4. the key for `kid`: a sink that holds none has bytes it cannot read, which SPEC §3.1 check 6
   does not hold (`prior_not_held`, with `set_key_absent`);
5. the plaintext's SHA-256 is `inner` (`set_key_mismatch`: another key, or a header that
   misstates its set; the set is not held).

Opened, the plaintext is the set in its inner form, read as that form is read (§9, or the
capability's one file). The set has two identities, the pin's digest over the sealed bytes and
`inner`, and SPEC §3.1 check 5 runs over both, so a set revoked under one is not reached under
the other.

- **The key.** `kid` names the key as ISO/IEC 23001-7 names a content key, by a 16-byte
  identifier, and the key is a 16-byte AES-128 key. An origin releases it as it releases a
  content key, by a key delivery that carries keys by their identifier (W3C Clear Key, or a
  content protection system: [key-release](key-release.md) §3.2). This revision registers no
  scheme of key-release §3.1 for it, so key-release's proxy form names none.
- **Sealing.** An encoder **MUST NOT** seal two different plaintexts under one key with counter
  ranges that overlap, and **SHOULD** use a fresh key for each sealed set.
- **Ranges.** A large sealed set is fetched by range from several peers as a chunk tree whose
  inner form is `wai.prior.sealed` (§19), whose ranges verify before the key is used.

### 18.3 Leakage

- **A content-derived set carries its content.** Parameters fitted to a title's frames can hold
  features of those frames, and a decode through them can reproduce them; how much is not
  bounded by anything in this extension, and WAI states no measure of it. A set whose bound
  statement says `content_derived: true`, fitted to content that is under access control,
  **SHOULD** be sealed (§18.2), its key released only to sinks entitled to that content, and
  **SHOULD** state `redistribute: false`.
- **A digest names a title.** The digest of a per-title prior names the title it was fitted to,
  so a list of the sets a sink holds says which titles it decoded. The Sink Capability
  Descriptor's `held_sets`, `Available-Dictionary` and a fetch by digest each disclose a held
  set, and [http-delivery](http-delivery.md) §12.5 states what a sink may disclose.
- **A sealed header names its plaintext.** `inner` is the plaintext's SHA-256: a party that
  holds the plaintext can tell which sealed set holds it, and learns nothing else of it. `kid`
  is shared by every set sealed under one key, so a fresh key for each set keeps sets from being
  linked by their key.
- **Receipts.** A receipt that names the set a decode read names a title for a per-title prior,
  and is disclosed as the receipt is.

**Reference implementation and corpus.** `prior_carriage::usage` reads a statement;
`prior_carriage::sealed` seals and opens a set (`seal`, `read_header`, `open`; counter mode
through the AES-128 that the `hpke` feature already links); `prior_carriage::privacy` builds
`held_sets` (http-delivery §12.5). The reference pin verifier reads no sealed set
(`pin::READABLE_FORMS` holds `wai.prior.set`), so the reference sink refuses a pin in this form
with `form_unreadable`; a sink that holds the key calls `prior_carriage::sealed::open` and then
holds the plaintext under its inner form. `prior_carriage::locations::fetch_set` reads the
statement a listing binds once it holds the listing's files. The corpus holds usage
statements, `title` sealed with a content-derived statement (`files/title.wsk1`) and `generic`
sealed as a capability's one file (`files/generic.wsk1`), each under the corpus's published
test key, which protects nothing: opened with the key; without it, refused `set_key_absent`;
under another key and with a ciphertext byte changed, refused `set_key_mismatch`; and headers
broken one way each, among them the inner forms of a coded form, a listing, a sealed set and a
tree. It holds three fetches of a listing with a file named `wai-usage.json`: one at the
top-level path, held with the terms it states; one there that does not read, which leaves the
set not held (`set_usage_malformed`); and one at the path `a/wai-usage.json`, a file of the set
that binds nothing.

## 19. The chunk-tree form `wai.prior.tree`

A set's SHA-256 can be checked only once every byte of the set is held, so a large set fetched
from peers that may serve other bytes is verified only at its end, and a changed byte costs the
whole fetch. An envelope does not have that problem: its content hash is a BLAKE3 tree whose
parts verify on their own ([http-delivery](http-delivery.md) §6). The chunk-tree form gives a set
the same: a small **tree head** names the set by its length, its SHA-256 and its BLAKE3 hash, and
lists a BLAKE3 chaining value for each **piece**, a run of 2^`g` of BLAKE3's 1024-byte chunks. A
pin in the form `wai.prior.tree` names the head's SHA-256, so the head is checked as any set is
(§15), and every piece then verifies as it arrives, from any peer.

### 19.1 The head

All integers are little-endian.

| offset | size | field |
|---|---|---|
| 0 | 4 | magic `WTR1` |
| 4 | 1 | `g`, 0 to 16: a piece is 1024 · 2^`g` bytes (`P`) |
| 5 | 1 | `k`, the inner form's length, 0 to 64 |
| 6 | `k` | the inner form, bytes `!` to `~`: a form §18.2 admits inside a sealed set, or `wai.prior.sealed` |
| 6 + `k` | 8 | `L`, the set's length in bytes, at least 1 |
| 14 + `k` | 32 | `inner`, the SHA-256 of the set's bytes: its digest in its inner form |
| 46 + `k` | 32 | `root`, the BLAKE3 hash of the set's bytes |
| 78 + `k` | 4 | `n`, the number of pieces: ⌈`L` / `P`⌉, 2 to 65 536 |
| 82 + `k` | 32 · `n` | the chaining value of each piece, in order |

The head is exactly `82 + k + 32·n` bytes. Piece `i` is bytes `i·P` to `min((i+1)·P, L)` of the
set; its **value** is the non-root chaining value of those bytes as the subtree of BLAKE3's tree
over the whole set whose first chunk counter is `i · 2^g` (the BLAKE3 specification §2.1, in
hash mode). Every piece but the last is 2^`g` whole chunks, so each piece is a
subtree of that tree, and the values merge to its root: over `m` values, with `m` at least 2, the
left child is the merge of the first `2^⌊log₂(m−1)⌋` and the right child of the rest, a parent
node without the ROOT flag below the top and with it at the top. That root is `root`, which is
the BLAKE3 hash of the set's bytes: hashing a held set with any BLAKE3 implementation checks it
against its head.

A sink reads a head in this order, the first check that fails being the reason:

1. the layout above (`tree_head_malformed`): the magic, `g`, `k`, `L`, `n` equal to
   ⌈`L` / `P`⌉ and from 2 to 65 536, and the length;
2. the inner form, which is admitted (`tree_inner_form`): none, `wai.prior.safetensors`,
   `wai.prior.gguf` or `wai.prior.sealed`, as the table above lists, and no other string;
3. the root the values merge to is `root` (`tree_root_mismatch`).

A set that fits in one piece is pinned in its inner form: its head would add nothing.

### 19.2 Fetching by range

The set's bytes are served as a one-file set under `inner`, at `<root><inner>` below any set
root (§15), so every server that holds the set serves it whole or by range. A sink that holds
the head:

1. requests pieces with `Range: bytes=<i·P>-<min((i+1)·P, L) − 1>`, one piece or several whole
   pieces in a request, from as many sources as it likes at once, and checks each response as
   [http-delivery](http-delivery.md) §7.1 checks a range response (`content_coding_present`,
   `content_range_mismatch`, and the others there), a server that does not answer being
   `set_location_unavailable`;
2. checks each piece against its value as it arrives, and discards one that does not match
   (`tree_piece_mismatch`), fetching that piece from another source: a changed byte costs one
   piece, and a verified piece is never fetched again;
3. once every piece is held, requires the set's SHA-256 to be `inner`
   (`tree_digest_mismatch`: a head that misstates its set, which is not held).

A piece that no source yields leaves the set not held (SPEC §3.1 check 6, `prior_not_held`). The
held set is then the inner form's set, whose digest is `inner`: it satisfies a pin in its inner
form too. The set has two identities, the head's digest and `inner`, and SPEC §3.1 check 5 runs
over both. A sink sends no `Available-Dictionary` with a range request (http-delivery §8.8).

The order of the sources is the sink's; the reference fetches piece `i` first from source
`i mod m` of its `m` sources, then from each source after it in turn.

**Reference implementation and corpus.** `prior_carriage::tree` writes and reads a head
(`write_head`, `read_head`, `root_of`), checks a piece (`piece_verifies`) and fetches every piece
from several sources over the responses its caller supplies (`fetch_pieces`), through the BLAKE3
hazmat API the HTTP head proof uses; its unit tests require `root` to be the BLAKE3 hash for
every piece size and set length they try. The reference pin verifier reads no tree head
(`pin::READABLE_FORMS`), so the reference sink refuses a pin in this form with
`form_unreadable`. The corpus holds the heads of `generic` in pieces of one chunk and of two
(`files/generic.wtr1`, `files/generic-g1.wtr1`) and of the sealed `title`
(`files/title-sealed.wtr1`, inner form `wai.prior.sealed`), heads broken one way each (among
them the inner forms of a coded form, a listing, a tree and a string no form registers), and
fetches from two peers: both whole; one with a byte changed in piece 3, refused at that piece,
which the other peer then yields; one that does not answer; both changed at one piece, which
leaves the set not held; one with a content coding; one whose bytes end early; the sealed
`title`; and a head whose `inner` misstates its set.

## 20. Refusals of §15 to §19

The reasons of http-delivery §8.7 and §8.8 are listed in its §13. This section's are:

| code | where |
|---|---|
| `plan_malformed` | §17: a plan with a span that does not run forward, a cap of 0, generations out of epoch order or named twice, a coding against a generation that is not an earlier one, a title of no stated generation, a sink that holds or fetches what the plan does not state, or a member of another type |
| `set_usage_malformed` | §18.1: a statement that does not read, and a listing whose bound statement does not read, which leaves the set not held; §18.2 step 3 |
| `sealed_malformed` | §18.2 step 1 |
| `sealed_inner_form` | §18.2 step 2 |
| `set_key_absent` | §18.2 step 4: the set is not held (`prior_not_held`) |
| `set_key_mismatch` | §18.2 step 5: the set is not held |
| `tree_head_malformed` | §19.1 step 1 |
| `tree_inner_form` | §19.1 step 2 |
| `tree_root_mismatch` | §19.1 step 3 |
| `tree_piece_mismatch` | §19.2 step 2: that piece is fetched from another source |
| `tree_digest_mismatch` | §19.2 step 3: the set is not held |

## Appendix A — The integer payload's arithmetic coding (normative)

The integers of an `NNR_PT_INT` payload are binarised and coded with context-adaptive
binary arithmetic coding. Every quantity is an integer; `>>` is an arithmetic shift
(division by a power of two rounding toward negative infinity), and `lz(x)` is the number
of leading zero bits of `x` as a 32-bit word.

**Contexts.** With `G = cabac_unary_length_minus1 + 1` greater-than flags there are
`L = 24 + 3 + 2G + 32 + 4` contexts, numbered from 0: 0 to 23 for significance (three for
each of eight quantiser states; with `dq_flag` 0 only 0 to 2 are used), 24 to 26 for the
sign, `27` to `26 + 2G` for the greater-than flags (two per flag, positive then negative),
`27 + 2G` to `58 + 2G` for the remainder's prefix, and four more; the one numbered
`L − 2` codes the initialisations. A context holds `s0` (a signed 8-bit integer), `s01`
(a signed 16-bit integer) and two shifts `h0`, `h1`. Initialisation `j` (0 to 8), the row
`[b0, b1, v01, v0]` of table A.3, sets `s0 = v0`, `s01 = v01`, `h0 = b0 + 4`,
`h1 = b1`. A context's most probable symbol is 1 when `s01 ≥ 0`, else 0. After a bin
`b`, with `σ = +1` when `b = 1` and `−1` otherwise:

```
s1  = s01 − 16·s0
s0  = wrap8 ( s0 + σ·( C[16 + ((σ·s0) >> 3)] >> h0 ) )
s1  =         s1 + σ·( C[16 + ((σ·s1) >> 7)] >> h1 )
s01 = wrap16( s1 + 16·s0 )
```

where `wrap8` and `wrap16` keep the low 8 and 16 bits as two's complement and `C` is
table A.2 (an index outside it is `nnc_malformed`). A context's least-probable range for
a coder range `R` is `T[|s01 >> 7| + (R & 0xE0)]`, `T` being table A.1 (an index
outside it is `nnc_malformed`).

**Decoding.** The coder starts with `range = 510`, `value = 256·B0 + B1` from the
payload's first two bytes (fewer: `nnc_truncated`), `need = −8`, and two bytes read. Reading
a byte past the payload is `nnc_truncated`.

```
bin(ctx):    r = T(ctx, range); m = range − r
             if value < m·128:  b = mps(ctx); range = m
             else:              value −= m·128; range = r; b = 1 − mps(ctx)
             n = lz(range) − 23; range <<= n; value <<= n; need += n
             if need ≥ 0: value += readbyte() << need; need −= 8
             update(ctx, b); return b
bypass():    value = 2·value; need += 1
             if need ≥ 0: value += readbyte(); need = −8
             if value ≥ range·128: value −= range·128; return 1
             return 0
bypass(k):   k bypass bins, the first the most significant bit of a k-bit number
finish():    range −= 2
             value ≥ range·128, else nnc_malformed          (the terminating bin)
             ((last byte read) << (8 + need)) & 0xFF = 0x80, else nnc_malformed
             the payload's length is the number of bytes read
```

**The payload.** First the initialisations: for each context `i` from 0 to `L − 5`,
skipping 3 to 23, decode a bin with context `L − 2`; when it is 1, `j = 1 + bypass(3)`,
else `j = 0`; initialise context `i` with `j` (context `L − 2` keeps adapting). Then each
of the tensor's elements in row-major order, `p` being the previous element's value (0
before the first) and `c(p)` 0, 1 or 2 as `p` is zero, negative or positive:

```
if bin(c(p)) = 0: value 0
else:
  v = 1; s = bin(24 + c(p))
  g = bin(27 + s); k = 1
  while g = 1 and k < G: v += 1; g = bin(27 + s + 2k); k += 1
  if g = 1:
    v += 1; q = 27 + 2G; rem = 0
    if bin(q) = 1:
      rem = 1; q += 1; e = 1
      loop: q ≥ 59 + 2G → nnc_malformed
            if bin(q) = 0: stop
            rem += 2^e; q += 1; e += 1
      rem += bypass(e)
    v += rem
  v past 2^31 − 1 → nnc_malformed
  value v, or −v when s = 1
```

then `finish()`.

**Encoding.** The writer's coder starts with `low = 0` (a 32-bit word: every addition and
left shift below keeps its low 32 bits), `range = 510`, `left = 23`, a buffered byte
`B = 0` and `n = 0` bytes buffered.

```
out():       lead = low >> (24 − left); left += 8; low &= 0xFFFFFFFF >> left
             if lead = 0xFF: n += 1
             else if n > 0: c = lead >> 8; emit (B + c) mod 256; B = lead mod 256
                            emit (0xFF + c) mod 256, n − 1 times; n = 1
             else: n = 1; B = lead
bin(b, ctx): r = T(ctx, range); range −= r
             if b = mps(ctx): if range < 256: range = 2·range; low = 2·low; left −= 1
             else: k = lz(r) − 23; low += range; range = r << k; low <<= k; left −= k
             if left < 12: out()
             update(ctx, b)
bypass(b):   low = 2·low; if b = 1: low += range
             left −= 1; if left < 12: out()
finish():    range −= 2; low += range; low <<= 7; range = 256; left −= 7
             if left < 12: out()
             if low >> (32 − left) ≠ 0: emit (B + 1) mod 256; emit 0x00, n − 1 times
                                        low −= 2^(32 − left)
             else: if n > 0: emit B
                   emit 0xFF, n − 1 times
             low = 2·(low >> 8) + 1; left −= 1; low <<= 32 − (24 − left)
             for i = 0, 8, 16, … while i < 24 − left: emit (low >> (24 − i)) & 0xFF
```

The writer codes every initialisation as 0: for each context `i` from 0 to `L − 5`,
skipping 3 to 23, a bin 0 with context `L − 2`. Then each value `v`, `p` as above:

```
bin(v ≠ 0, c(p))
if v ≠ 0:
  s = 1 if v < 0 else 0; bin(s, 24 + c(p))
  r = |v| − 1; g = (r > 0); bin(g, 27 + s); k = 1
  while g = 1 and k < G: r −= 1; g = (r > 0); bin(g, 27 + s + 2k); k += 1
  if g = 1:
    r −= 1; q = 27 + 2G
    if r = 0: bin(0, q)
    else: bin(1, q); base = 1; e = 1; q += 1
          while r > base + 2^e − 1: bin(1, q); base += 2^e; q += 1; e += 1
          bin(0, q); r − base as e bypass bins, most significant first
```

then `finish()`.

**Table A.1** — `T`, 256 entries, row `x` holding entries `32x` to `32x + 31`:

```
128 112  97  84  74  65  57  50  45  39  34  30  27  23  20  18  15  14  12  11  10   9   7   7   5   5   4   4   3   3   2   2
142 125 108  93  82  72  63  56  50  43  38  33  30  26  22  20  17  16  13  12  11  10   8   8   6   6   5   5   3   3   2   2
156 137 119 103  90  79  70  61  55  48  42  37  33  28  24  22  19  17  15  13  12  11   9   9   6   6   5   5   4   4   2   2
171 150 130 112  99  87  76  67  60  52  46  40  36  31  27  24  21  19  16  15  13  12  10  10   7   7   6   6   4   4   3   3
185 162 141 121 107  94  82  73  65  56  50  43  39  34  29  26  22  21  17  16  14  13  11  11   8   8   6   6   4   4   3   3
199 175 152 131 115 101  89  78  70  61  54  47  42  36  31  28  24  22  19  17  15  14  12  12   8   8   7   7   5   5   3   3
213 187 163 140 123 108  95  84  75  65  58  50  45  39  33  30  26  24  20  18  16  15  13  13   9   9   7   7   5   5   3   3
228 200 174 150 132 116 102  90  80  70  62  54  48  42  36  32  28  26  22  20  18  16  14  14  10  10   8   8   6   6   4   4
```

**Table A.2** — `C`, 32 entries:

```
2512 2288 2064 1840 1616 1392 1168 944 720 560 464 368 272 208 144 80
  64   64   64   64   64   64   64  64  64  64  64  64  64  64  64  0
```

**Table A.3** — the nine initialisations `[b0, b1, v01, v0]`:

```
0: [1, 4, 0, 0]       1: [1, 4, -1310, -41]   2: [1, 4, 3039, 95]
3: [0, 5, 0, 0]       4: [2, 6, 962, 30]      5: [2, 6, 3039, 95]
6: [2, 6, -673, -21]  7: [3, 5, 0, 0]         8: [3, 5, 962, 30]
```
