moq-streaming-format: declare WAI as a MoQ streaming format #85

Merged
dcharlot merged 1 commit from wai/moq-streaming-format into main 2026-09-10 12:21:10 -04:00

View file

@ -0,0 +1,139 @@
# 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. |
| `acquisition` | string | Acquisition class per [energy-measurement](energy-measurement.md) §2. |
| `group_receipt` | 32 B | BLAKE3 of the group receipt covering this object. |
- `acquisition` **MUST** accompany `joules_micro`. 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 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.