# WAI Extension: MoQ Streaming Format > Status: Draft, and deliberately tracking rather than pinning — MOQT is > pre-Working-Group-Last-Call and its text still moves. Declares WAI as a > **streaming format** over Media over QUIC Transport, so a WAI envelope is a > first-class MOQT object rather than an opaque payload inside someone else's > container. No new transport: WAI defines none by charter, and this extension > does not change that. Field semantics and rules over them only — never MOQT's > byte encoding. > Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174. ## 1. Why a streaming format MoQ separates two things that other stacks fuse: - **MOQT** (`draft-ietf-moq-transport`) moves objects, in groups, on tracks. It does not know what an object means. - **MSF** (`draft-ietf-moq-msf`) says what objects mean: it fragments a stream into objects, declares what a publisher emits in a **catalog**, and sets prioritisation. WAI already references MoQ for confidentiality (MLS + SFrame; see [confidentiality](confidentiality.md)). That binding treats MoQ as a pipe. This one treats it as what it is — a two-layer design with an open slot at the upper layer, which is precisely where a container that carries capability-dispatched objects belongs. The alignment is structural, not aspirational. MSF fragments a stream into objects in groups; WAI envelopes are already objects, and [jwp-receipts](jwp-receipts.md) already commits per object and signs per group. The two layers agree on the unit without either being changed. ## 2. Precedent: the slot is open, and cheaply MSF's catalog names a format in its `packaging` field, over a value set MSF's own text fixes (`loc`, `mediatimeline`, `eventtimeline`, `moqlog`, `moqmetrics`, `catalog`). There is no central streaming-format registry. Read alone, that is closed. `draft-ietf-moq-cmsf` shows it is not. CMSF is a sibling Internet-Draft that declares `packaging` value `cmaf`, stating that it *extends the allowed packaging values defined in MSF*; inherits MSF wholesale — *all of the specifications, requirements and terminology defined in MSF apply to implementations of this extension*; adds two track-level catalog fields; and registers nothing: **this document has no IANA actions**. LOCMAF is a second instance of the same move. So the path is a sibling draft with no registry action and no permission sought. This extension is the WAI-side statement of what such a draft would say. ## 3. The packaging value A track carrying WAI envelopes **MUST** declare `packaging` value `"wai"`. - Every object on such a track **MUST** be exactly one WAI envelope (`WAI1` magic + manifest + payload), whole. An object carrying a fragment of an envelope, or more than one, is not this packaging. - The object boundary **MUST** be the envelope boundary. This is what makes the receipt's per-object commitment (`jwp-receipts` §2.1) and MOQT's object identity the same unit; if they diverge, every guarantee that composes them is void. - A sink that does not recognise `"wai"` **MUST NOT** attempt to interpret the objects. MSF's tolerant-parser rule covers unknown *fields*; it does not license guessing at unknown *packaging*. ## 4. Catalog declaration A WAI track's catalog entry **MUST** declare, in addition to MSF's required fields, the capabilities a sink needs to dispatch what the track carries: | field | type | meaning | |---|---|---| | `wai_capabilities` | array of string | Capability strings (WAI SPEC.md §4) that objects on this track may dispatch to. | | `wai_determinism` | string | The weakest tier any object on the track claims — see [determinism-tiers](determinism-tiers.md). Absent means no tier is claimed. | | `wai_receipts` | boolean | Whether objects carry receipts per §5. | - `wai_capabilities` **MUST** be exhaustive for the track. A publisher that dispatches to a capability it did not declare has broken the catalog's purpose, which is letting a sink decide **before** subscribing whether it can play what it is about to receive. - A sink **MUST NOT** subscribe on the assumption that an undeclared capability will not appear, and **MUST** treat an undeclared capability at dispatch as a protocol error rather than falling back silently. - `wai_determinism` is the **weakest** tier on the track, not the strongest. Declaring the strongest would let a track advertise a guarantee most of its objects do not meet. These are custom catalog fields under MSF's extension rule; they are namespaced by their `wai_` prefix and MUST NOT collide with MSF-defined names. ## 5. The per-object property MSF §12 defines **MSF Properties** at **Track** and **Object** scope, with an IANA registry of property types that today holds essentially one entry (`MSF_COMPRESSION`). CMSF adds track-level catalog fields and defines **no per-object property**. The object-scope slot is empty. A WAI receipt is already per-object. This extension therefore defines one object-scope property, `WAI_RECEIPT`, whose value is the object's receipt commitment: | field | type | meaning | |---|---|---| | `content_hash` | 32 B | `jwp-receipts` §2.1 BLAKE3 over the envelope bytes. | | `joules_micro` | u64 | Microjoules producing this object; `0` is the unmetered marker, never 0 J ([energy-measurement](energy-measurement.md) §2). | | `acquisition` | string | Acquisition class per [energy-measurement](energy-measurement.md) §2; empty when `joules_micro` is `0`. | | `acquisition_evidence` | bytes | For `OnChipCounter` and `CalibratedInstrument`, the evidence that follows the tag byte in `energy-measurement.md` §2.7 (declared uncertainty, then filtering state or calibration reference). Empty for every other class. | | `group_receipt` | 32 B | The link hash of the group receipt covering this object (`jwp-receipts` §3 step 3). | - A non-zero `joules_micro` **MUST** be accompanied by `acquisition`. A joule figure without its acquisition class is exactly what `energy-measurement.md` §2 forbids, and putting it on the wire does not make it acceptable. - A zero `joules_micro` is the unmetered marker: `acquisition` **MUST** be empty and `acquisition_evidence` empty, since a class beside a zero figure claims a measurement that did not occur (`energy-measurement.md` §2). A sink **MUST NOT** present the marker as a figure of zero joules, and **MUST** discard a property that breaks this bullet or the one above (`property_invalid`). - `acquisition_evidence` **MUST** be present and non-empty for a refined hardware class (`OnChipCounter`, `CalibratedInstrument`), and empty otherwise — including for legacy `HwShunt`, which carries no evidence. A refined class without its declared uncertainty is refused by `energy-measurement.md` §2 on the same terms as a figure without a class. A property written before this field existed has no `acquisition_evidence`; a reader treats its absence as empty, which is valid only for the classes that carry none. - No signature covers this property. A sink **MUST NOT** report `acquisition` or `acquisition_evidence` as signed unless they and `joules_micro` equal a signed statement it holds of the same object, which is one of: - the label in the object's Merkle leaf, once the object receipt has been accepted under `jwp-receipts` §3 against the group receipt `group_receipt` names — `group_receipt` must then name that group; or - an `energy` claim about the object that it has accepted under `jwp-receipts` §3.1. A claim names no group, so `group_receipt` is outside what it states. Where such a statement gives another figure, class, evidence or group, the sink **MUST** discard the property (`property_disagrees`). Where it holds none, the class is outside every signature, and the sink reads the figure as unlabelled. - A class read as signed is the statement of the key that signed it: the group receipt's `signer_pubkey` for a leaf, the claim's `signer_pubkey` for an `energy` claim. A sink **MUST** report that key with the class, and **MUST NOT** report a class a claim signs as the publisher's unless the claim's signer is a key it holds as the publisher's. Anyone can sign an `energy` claim, a relay that rewrites this property included. - A relay **MUST** preserve this property unchanged, per `jwp-receipts` §4.1. A relay that recomputes it is asserting something it did not measure. - Absence of the property is not evidence of absence of a receipt; receipts MAY ride elsewhere (§1 of `jwp-receipts` lists sidecar and trailer carriage). A sink **MUST NOT** infer that an object without the property is unattested. ## 6. What this extension does not do Stated so it is not re-argued: - It does **not** define, profile, or restate MOQT's wire encoding — not the object header, not the extension-header byte layout, not the control messages. Those are MOQT's, and the property that makes this binding cheap is that WAI rides a transport instead of defining one. - It does **not** replace CMSF or LOC. A publisher with CMAF-packaged media should use CMSF; this packaging is for tracks whose objects are WAI envelopes. - It does **not** make MoQ WAI's transport. WAI remains carrier-agnostic; this is one binding among the several `jwp-receipts` §1 anticipates. - It does **not** pin a MOQT draft revision. MOQT is pre-Last-Call; an extension that pinned a moving target would be wrong within a meeting cycle. Where MOQT and this text disagree, MOQT wins and this text is the thing that must change. ## 7. Framing The delivery industry is converging on MoQ, and the layer above it is where formats declare themselves. A container that carries instructions, dispatches by capability, and commits per object has a natural home there — not because it competes with the transport, but because the transport deliberately left the question of meaning to someone else.