open-standards/wai/extensions/carousel.md
Transaction Science 793ed1f2dc
All checks were successful
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 7s
wai-audit collector and player integration / does this change touch it (pull_request) Successful in 10s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 12s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 14s
WAI operation catalogue / does this change touch it (pull_request) Successful in 13s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (pull_request) Successful in 13s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 14s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 7s
WAI HTTP delivery / WAI HTTP · does this change touch it (pull_request) Successful in 6s
wai-fleet service / does this change touch it (pull_request) Successful in 14s
WAI neural sink gates / does this change touch it (pull_request) Successful in 13s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 12s
wai-quantum for JavaScript / does this change touch it (pull_request) Successful in 9s
wai-ledger service / does this change touch it (pull_request) Successful in 14s
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Successful in 14s
wai-key-proxy / does this change touch it (pull_request) Successful in 16s
WAI conformance / does this change touch it (pull_request) Successful in 31s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 32s
wai-quantum studio and desktop / does this change touch it (pull_request) Successful in 6s
WAI energy receipts / does this change touch it (pull_request) Successful in 33s
wai-sink-android native sink library / does this change touch it (pull_request) Successful in 8s
wai-sink-swift native sink package / does this change touch it (pull_request) Successful in 7s
WAI Studio / does this change touch it (pull_request) Successful in 8s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 9s
wai-web wasm32 / does this change touch it (pull_request) Successful in 25s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 5s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 55s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 1m11s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m58s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (pull_request) Successful in 1m22s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 1m51s
wai-audit collector and player integration / collector · linux (pull_request) Successful in 1m32s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 2m31s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m51s
WAI neural sink gates / the exact JPEG-AI decoder reports its path (pinned inputs, required) (pull_request) Successful in 2m2s
WAI conformance / fast integer kernels, every x86_64 kernel set (AVX-512 silicon) (pull_request) Successful in 3m36s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 4m32s
wai-fleet service / service · linux (pull_request) Successful in 2m42s
wai-key-proxy / proxy · linux (pull_request) Successful in 57s
wai-pack / wai-pack · linux (pull_request) Successful in 3m19s
WAI conformance / faces from keypoints under wasm32-wasip2 (wasmtime) (pull_request) Successful in 1m30s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 27s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 5m59s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 4m11s
WAI operation catalogue / the catalogue and every door · linux (pull_request) Successful in 5m56s
wai-ledger service / service · linux (pull_request) Successful in 1m50s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 7m18s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 1m7s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 3m48s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (pull_request) Successful in 7m43s
wai-quantum for JavaScript / javascript · linux (pull_request) Successful in 3m41s
wai-fleet service / service · macos (pull_request) Successful in 48s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 3m39s
wai-quantum studio and desktop / desktop app · linux (pull_request) Successful in 4m54s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 3m2s
wai-pack / wai-pack · macos (pull_request) Successful in 3m27s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 5m55s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 13m52s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 5m28s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 16m34s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 11m38s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 27s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m7s
wai-ledger service / service · macos (pull_request) Successful in 1m6s
wai-quantum studio and desktop / desktop app · windows (pull_request) Successful in 9m35s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 10m56s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 17m20s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 18m48s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 24m50s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 18m38s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m31s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 7m3s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m46s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 8m4s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m47s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 17m16s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 7m47s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 34m23s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 21s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 16s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 7m5s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 18s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 37m20s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 10m52s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 18m17s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 11m18s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 39m59s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 15s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 40m12s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 50s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m42s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 3m47s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 17m30s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 18m34s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 14m28s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 14m15s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 30m4s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h18m5s
wai/one-way-delivery, converted to the layout of the fix: no shared append point
The change of wai/one-way-delivery (f1258784d..987625394, 28 commits), on the fix branch: its
changelog entries as files of wai/changes/, its wai-conformance.yml edits as step files,
corpus files and test tags, and every other file as the branch has it.

- 25240c4f0 wai: timeliness — when each object of a group is of use, and whether each holder held it in time
- c84992362 wai: timeliness_verify.py — the timeliness corpus's second implementation
- 44036fcdc wai: timeliness in the registry, SPEC §5, the changelog and CI; http_receipts.py checks its claims
- 27ce6754c wai: claim_verify.py lists not-held-by-deadline, and the claim corpus holds a session that switches for it
- 73d8d8eb9 wai: timeliness corpus — each holder's own line in key order, a holder's earliest fallback, and §7.2–§7.3's unreached plan rules
- 64c735f0c wai: the files timeliness changes are clippy-clean — a let chain, and the fetch callback's type allowed
- b72dc36bf wai: rung price — what delivering a rung costs, by bearer and direction, and which option a comparer takes
- 4e905e213 wai: rung_price_verify.py — the rung price corpus's second implementation
- 711fa6126 wai: rung price in the registry, SPEC §5, the changelog and CI
- 8ab70654e wai: rung price corpus — a refusal for every form rule 1 and §6.1 set, and the neighbour order a plan gives
- 1bc465959 wai: rung price ranks energy by checked evidence — a class counts only on the seller's own per-hop records, current and under a confirmed key
- 9e97997d9 wai: rung_price — the evidence text bound at its exact sizes, and a key confirmed for another class confirming nothing
- 8f1168683 wai: rung price corpus — a key confirmed for another class, the uncertainty product, each edge and order of the evidence verdict, and the evidence a plan read
- 7330e26ff wai: rung price — §6.1 links jwp-receipts at its first mention, and §10 says a record's age is its room's word
- 12c099457 wai: cache authority — who served what a node holds, and on whose authority
- f8f5d3e09 wai: cache_authority_verify.py — the cache authority corpus's second implementation
- 354146619 wai: cache authority in the registry, SPEC §5, the changelog and CI; its corpus holds what §12 states
- 55c7f3031 wai: timeliness §6 reads holdings records alone; cache-authority §9 derives the lines that read every kind
- b8fc6f02b wai: cache authority's lines read records as timeliness does, its deadline claim meets the envelopes held, and its corpus fixes each order and instant
- 91c5291cf wai: the files cache authority changes are clippy-clean — a boxed envelope, the base's names named once, slices borrowed
- 8e479daff wai: a held envelope boxes both its forms, so neither outweighs the other
- 3ec8da807 wai: impression aggregates — ad presentations counted over a bearer with no return path
- 0433a35c3 wai: impression_aggregate_verify.py — the impression aggregates corpus's second implementation
- 7d8e150e4 wai: impression aggregates in the registry, SPEC §5, the changelog and CI; its corpus states each receipt whole and a control for every malformed file
- d5e8ace02 wai: impression aggregates' size bounds are checked at their edge, and §4.3's decides no outcome
- 4bc8e13bd wai: impression aggregates' table totals are exact, and a receipt given twice is checked when either occurrence was
- 3c9f20524 wai: key_log's two result enums keep their public form, and say so to clippy
- 987625394 wai: Item::with_authority and Count::instance_received build only with the feature that calls each

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-05 01:45:32 -05:00

510 lines
32 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WAI Extension: Carousel Schedule
> Status: Draft. Registers the record `wai.bearer.carousel`: a publisher's signed schedule of
> when each object of a group passes on a bearer instance, and with which application-layer
> forward error correction. On a bearer with no return path a receiver cannot ask for what it
> missed: it holds an object only if the passes it heard carried enough encoding symbols. The
> schedule says what was planned to be sent, in a jwp-receipts claim of class **schedule**
> (jwp-receipts §2.4.16, §4 here), signed by the group's key beside the group receipt and the
> transmission claim of [bearer-receipts](bearer-receipts.md) §4. From it a verifier derives,
> for each object, when a receiver whose losses stay within a stated bound holds it (§6): the
> deadline a one-way bearer can promise, with the decoding failure the FEC code bounds. A
> receiver derives the passes it must listen to and when it may turn its radio off (§7). WAI
> defines no transport and no code: the codes are RaptorQ (RFC 6330) and Compact No-Code
> (RFC 5445), and the schedule declares their parameters. The reference implementation is the
> `carousel` module of `wai-rs` (feature `carousel`), with the class's body in
> `claim_receipt::schedule`; the corpus is
> [`live-conformance/carousel/`](../live-conformance/carousel/), and its second implementation
> is `live-conformance/carousel_verify.py`.
> Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174.
>
> Texts read for this revision: RFC 6330 (RaptorQ) with its verified erratum 5548, RFC 5445
> (Compact No-Code) and RFC 5052 §9.1 (block partitioning). A clause number of one of them in
> this text is that RFC's. §11 also cites the IETF's IPR disclosures on RFC 5053, RFC 6330 and
> their drafts, read as the IETF datatracker shows them, and RFC 8179 §4.
## 1. Scope
In scope: the schedule claim (§4); how an object is divided into source blocks and symbols
under each code (§5); when an object is held by a receiver whose losses stay within a bound,
and the statements a verifier may check against it (§6); the passes a receiver listens to (§7).
Out of scope: encoding and decoding symbols, which are the codes' own (RFC 6330 §5, RFC 5445
§3); a transport, and how symbols are packed into packets; a model of a channel. Every
statement here holds for every pattern of loss within the stated bound (§2). Whether losses on a
channel are independent, and how often a bound is exceeded, is a judgement about that
channel, which a relying party makes and a schedule does not carry. Nothing here states
presentation, and nothing here states that any receiver heard anything: that is a
reconciliation's (bearer-receipts §5).
Relationship to the core spec: `wai.bearer.carousel` is a **record** ([SPEC](../SPEC.md) §5):
the schedule claim is a signed record a WAI tool emits and verifies. It names no payload format
and is not dispatchable.
## 2. Terms
- **Bearer instance**, **declaration**, **sink**, **relying party**: as bearer-receipts §2. A
declaration is a transmission claim that stands under bearer-receipts §6.2 step 4.
- **Source block**, **source symbol**, **repair symbol**, **encoding symbol**, **ESI** (encoding
symbol ID): as RFC 6330 §2 and RFC 5052. An object is divided into source blocks; a block of
*K* source symbols is sent as encoding symbols, each named by its ESI in that block.
- **Pass**: one transmission of encoding symbols of every source block of one object on a
bearer instance, from its start to its end. An object's passes are numbered from 1.
- **Instant**: a count of milliseconds since 1970-01-01T00:00:00Z, leap seconds not counted, as
[channel-lineup](channel-lineup.md) writes one.
- **Loss bound** *L*: an integer from 0 to 999,999, in parts per million. A receiver is
**within** *L* when, of the *m* encoding symbols of any one source block sent in any one
pass, it fails to receive at most ⌊*L* · *m* / 1,000,000⌋, whichever they are. It is a bound
on symbols: a relying party whose bound is stated on packets carrying several symbols each
converts it.
- **Overhead** *h*: 0, 1 or 2, the encoding symbols beyond *K′* a RaptorQ block is held at
(§5.3).
## 3. Why a schedule beside the receipt
The group receipt signs its objects and names no bearer (bearer-receipts §3); the transmission
claim names the bearer instance and attests that the publisher transmitted the group, which on
a bearer with no return path says nothing about any receiver. Between the two is what decides
whether a receiver that heard part of a transmission holds an object: how often each object
passes, for how long, and with how many repair symbols. That is a plan, made before anything
is sent, and it is a statement of the publisher's own:
- **A relying party can hold a deadline to it.** A publisher that offers an object to every
receiver within a loss bound by a deadline makes a promise that the schedule either supports
or does not (§6.4), checked with no receiver and no return path.
- **A receiver can plan with it.** It learns which passes add symbols it needs, and listens to
those only (§7). On a receiver powered by a battery the radio is a large part of its energy.
- **It changes no byte of what it schedules.** The schedule names the group by its link hash
and each object by its position and content hash, like a reconciliation. A group carried
before this extension, or by a party that does not use it, verifies exactly as before.
The schedule attests a plan, not a transmission: that is the declaration's, and the schedule
stands only beside one (§6.2). Neither attests that any receiver heard anything.
## 4. The schedule claim (`class: "schedule"`)
A publisher that transmits a group over a `multicast` or `unidirectional` bearer instance
**MAY** declare its schedule there in a `schedule` claim, one per bearer instance. Its
`subject_type` is `receipt` and its `subject` the group receipt's link hash (jwp-receipts §3
step 3). It is signed by the key that signed the group. It attests that the publisher
scheduled the passes it names, and nothing about what any sink received.
### 4.1 Body
| member | type | meaning |
|---|---|---|
| `bearer_id` | absolute URI | The bearer instance (bearer-receipts §2): the `bearer_id` of the transmission claim it schedules. |
| `objects` | array | The objects scheduled, one entry each (below). |
| `attests` | string | **MUST** be `"scheduled"`. Any string passes step 2; another value is refused at step 4. |
Each entry of `objects` has exactly these members:
| member | type | meaning |
|---|---|---|
| `leaf_index` | integer | The object's position in the group (jwp-receipts §2.2). |
| `content_hash` | 32 B hex | The object's content hash (jwp-receipts §2.1): what a receiver that decodes the object checks it against. |
| `fec` | string | The code: `raptorq` (RFC 6330, FEC Encoding ID 6) or `no-code` (RFC 5445, FEC Encoding ID 0). |
| `oti` | object | The code's object transmission information, as §5 reads it. For `raptorq`, exactly `transfer_length` (F), `symbol_size` (T), `source_blocks` (Z), `sub_blocks` (N) and `alignment` (Al), RFC 6330 §3.3.2 and §3.3.3. For `no-code`, exactly `transfer_length`, `symbol_size` (the encoding symbol length) and `max_block_length` (the maximum source block length, in symbols), RFC 5445 §3.2.2.2. Each an integer. |
| `repair` | integer | The repair symbols of each source block sent in each pass, beyond its source symbols (§5.4). |
| `esi` | string | `repeat`: every pass sends the same ESIs. `advance`: each pass sends ESIs no earlier pass sent (§5.4). |
| `first_ms` | integer | The instant the first pass starts. |
| `period_ms` | integer | The time from one pass's start to the next's. |
| `duration_ms` | integer | The time each pass lasts. |
| `count` | integer | The number of passes. |
`fec` and `esi` are read at jwp-receipts §3.1 step 2 against their enumerations, the members of
`oti` against the code `fec` names, `bearer_id` as an absolute URI, and every integer as an
unsigned 64-bit one (`field_type`).
### 4.2 Rules
Checked at jwp-receipts §3.1 step 4, in this order:
1. `attests` **MUST** be `"scheduled"` (`schedule_not_scheduled`).
2. `objects` has at least one entry, and its `leaf_index` values strictly increase
(`schedule_objects_malformed`): one entry for each object scheduled, in group order.
3. Each entry in order, the first of these to fail:
1. its `oti` is one its code admits, §5.1 or §5.2 (`schedule_oti_invalid`);
2. its symbols are ones its code can name, §5.4 (`schedule_symbols_invalid`);
3. its passes are well formed (`schedule_passes_invalid`): `count` and `duration_ms` are at
least 1; with `count` at least 2, `period_ms` is at least `duration_ms`, so one pass of
an object ends before its next starts; the last pass ends,
`first_ms` + (`count` − 1) · `period_ms` + `duration_ms`, at or before 253,402,300,799,999
(9999-12-31T23:59:59.999Z); and the octets its passes send, `bytes_sent` (§5.4), are at
most 2<sup>53</sup> − 1, the greatest integer a receipt states; each computed without
overflow.
### 4.3 Against the group
Checked at jwp-receipts §3.1 step 6 against the group receipt the verifier holds, which has
passed jwp-receipts §3 steps 1 and 2 and whose `group_start` is an RFC 3339 date-time
(`context_invalid` otherwise; another receipt is `context_mismatch`), the object receipts it
holds under that group, each of which has passed jwp-receipts §3 step 5, and the envelope bytes
of those it holds. In order:
1. the group's link hash is the claim's `subject` (`schedule_subject_mismatch`);
2. the claim's `signer_pubkey` is the group's (`schedule_signer_mismatch`): only the publisher
schedules its own transmission;
3. every `leaf_index` is less than the group's `leaf_count` (`schedule_leaf_out_of_range`);
4. no entry's first pass starts before the group does (`schedule_before_group`): ⌊`first_ms`
/ 1000⌋ is at least the seconds jwp-receipts §2.4.3 reads from `group_start`, its fraction
dropped. Nothing can be sent before it exists;
5. for each entry whose object receipt the verifier holds, the receipt's `content_hash` is the
entry's (`schedule_content_mismatch`); and for each whose envelope bytes it holds, their
length is `oti.transfer_length` (`schedule_length_mismatch`).
A schedule checked without the group stops at step 5 and is not counted by §6.
### 4.4 Authority
Confirmed under jwp-receipts §7, a schedule claim needs the authority `schedule`, which is not
pinned-only and is not `delivery`. An origin gives it to the keys that publish its groups, as it
gives `transmission`.
## 5. Blocks and symbols
### 5.1 RaptorQ
The `oti` of a `raptorq` entry, F, T, Z, N and Al, is one RFC 6330 admits when:
- F is from 1 to 942,574,504,275 (§3.3.2 as erratum 5548 corrects it: 56,403 symbols of
65,535 octets in each of 255 blocks);
- T is from 1 to 65,535 and a multiple of Al, and Al from 1 to 255 (§3.3.2, §3.3.3, §4.2);
- Z is from 1 to 255, the range of its 8-bit field (§3.3.3: the parameters are positive);
- N is from 1 to T / Al, so each sub-block has a sub-symbol of at least Al octets (§4.4.1.2);
- with *Kt* = ⌈F / T⌉, Z is at most *Kt*, so no source block is empty, and ⌈*Kt* / Z⌉ is at
most 56,403, *K′*<sub>max</sub> (§4.4.1.2, §5.1.2).
The object is then divided as RFC 6330 §4.4.1.2 divides it: (*KL*, *KS*, *ZL*, *ZS*) =
Partition[*Kt*, Z], where Partition[*I*, *J*] = (⌈*I* / *J*⌉, ⌊*I* / *J*⌋, *I* − ⌊*I* / *J*⌋ · *J*,
*J* − (*I* − ⌊*I* / *J*⌋ · *J*)). The first *ZL* source blocks have *KL* source symbols each and
the remaining *ZS* have *KS*. Each symbol is T octets; the last source symbol of the object is
padded to T.
### 5.2 Compact No-Code
The `oti` of a `no-code` entry, with L its `transfer_length`, E its `symbol_size` and B its
`max_block_length`, is one RFC 5445 admits when L is from 1 to 2<sup>48</sup> − 1, E from 1 to
65,535 and B from 1 to 2<sup>32</sup> − 1 (RFC 5445 §3.2.2.2; an object of no octets has
nothing to schedule), and the division of RFC 5052 §9.1 fits RFC 5445's 16-bit source block
number and encoding symbol ID (§3.2.1):
- the object has *Ts* = ⌈L / E⌉ source symbols, in *Nb* = ⌈*Ts* / B⌉ source blocks;
- *A*<sub>large</sub> = ⌈*Ts* / *Nb*⌉, *A*<sub>small</sub> = ⌊*Ts* / *Nb*⌋ and *I* = *Ts* −
*A*<sub>small</sub> · *Nb*: the first *I* blocks have *A*<sub>large</sub> source symbols and
the others *A*<sub>small</sub>;
- *Nb* is at most 65,536, and *A*<sub>large</sub> at most 65,536.
Every symbol is E octets but the object's last, which holds what remains of L.
### 5.3 What a receiver needs
A block of *K* source symbols is **held** when a receiver can recover it:
- **`no-code`**: when it has received every one of its *K* source symbols. There are no repair
symbols; a symbol missed is missed until a pass sends it again.
- **`raptorq`**: when it has received *K′* + *h* distinct encoding symbols of the block, where
*K′* is the least value at least *K* in RFC 6330 Table 2 (§5.6; its column of *K′* is restated
in Appendix A). RFC 6330 §5.8 bounds the decoder's failure to recover a block of *K′* source
symbols from *K′*, *K′* + 1 and *K′* + 2 encoding symbols, chosen uniformly at random, at
1 in 100, 1 in 10,000 and 1 in 1,000,000 on average. A block of *K* < *K′* symbols is padded
to *K′* with symbols the decoder knows (§5.3.1), so it may need fewer than *K′* + *h*
received; this text asks for the count §5.8 states its bound at, and no fewer.
An **object** is held when every one of its source blocks is.
### 5.4 The symbols a pass sends
Each pass sends, of each source block of *K* source symbols, *m* = *K* + `repair` encoding
symbols:
- `repeat`: ESIs 0 to *m* − 1 in every pass;
- `advance`: in pass *j*, ESIs (*j* − 1) · *m* to *j* · *m* − 1. The first pass holds the source
symbols (ESIs 0 to *K* − 1, RFC 6330 §4.4.2) and every later pass only repair symbols, none
sent before.
An entry's symbols are ones its code can name (§4.2 rule 3.2) when:
- **`no-code`**: `repair` is 0 and `esi` is `repeat`. The code has no repair symbols, and an ESI
past a block's last source symbol names nothing;
- **`raptorq`**: the greatest ESI sent fits the 24-bit field (RFC 6330 §3.2): with *KL* the
larger block's *K*, *KL* + `repair` is at most 2<sup>24</sup> for `repeat`, and `count` ·
(*KL* + `repair`) at most 2<sup>24</sup> for `advance`, computed without overflow.
The octets an entry's passes send, `bytes_sent`, are `count` · Σ *m* · T over its source blocks
for `raptorq`, and `count` · L for `no-code`, whose last symbol is short.
## 6. When an object is held
### 6.1 Inputs
The group receipt; the object receipts the verifier holds under it, each with its envelope
bytes where it holds them; the transmission and schedule claims it holds about the group, each
signer's in the order of its chain; a loss bound *L*; and an overhead *h*.
### 6.2 Steps
The loss bound and overhead are checked first: *L* above 999,999 is `loss_bound_invalid`, and
*h* other than 0, 1 or 2 is `overhead_invalid`; neither derives anything. Then:
1. **The group and its objects**: bearer-receipts §6.2 steps 1 and 2.
2. **The claims**: each claim, in order, under jwp-receipts §3.1 steps 1 to 5, then step 6: a
transmission claim by bearer-receipts §4.3 and a schedule by §4.3 here. A claim of another
class is `context_mismatch` at step 6. A claim refused at any step takes no further part.
3. **The declarations**: bearer-receipts §6.2 step 4.
4. **The schedules**: the accepted schedule claims by `bearer_id`. Two with one `bearer_id` and
different bodies set aside every schedule of that instance (`schedule_contradicted`): a
publisher that changes its plan for one transmission has stated neither, and a relying
party holds no promise that can change under it. Two with the same body are one. A schedule
is then set aside at the first of these that holds: step 3 set aside the declarations of its
`bearer_id` (`bearer_contradicted`); no declaration has its `bearer_id`
(`bearer_not_declared`); its declaration's `bearer` is `bidirectional`
(`schedule_on_bidirectional`), since a receiver with a path back asks for what it lacks and
is not served by a plan. Otherwise it **stands**.
5. **Availability**, for each entry of each standing schedule, by §6.3.
### 6.3 Availability
For an entry, pass *j* ends at the instant `first_ms` + (*j* − 1) · `period_ms` +
`duration_ms`. For each source block of *K* source symbols, with *m* = *K* + `repair` and *x* =
⌊*L* · *m* / 1,000,000⌋ the most a receiver within *L* misses of it in one pass, the first pass
after which a receiver within *L* holds the block is, under §5.3:
- **`raptorq`, `advance`**: the least *j* from 1 to `count` with *j* · (*m* − *x*) ≥ *K′* + *h*.
Every pass adds *m* − *x* symbols none before it sent.
- **`raptorq`, `repeat`**: 1 if *m* − *x* ≥ *K′* + *h*, and none otherwise. A later pass sends
the same ESIs, and the ones a receiver missed may be missed again: within *L*, nothing it adds
is certain.
- **`no-code`**: 1 if *x* is 0, and none otherwise, for the same reason.
The object is **available** at the end of the greatest of its blocks' passes, or is **not
available within the schedule** if any block has none. A verifier reports for each entry its
`available_ms` (or `null`), the pass, `bytes_sent` (§5.4), and, for `raptorq`, the RFC 6330
§5.8 bound at *h* as `failure_one_in` (100, 10,000 or 1,000,000); for `no-code` it is `null`, a
block held being recovered exactly.
### 6.4 Statements offered about an object or a group
A verifier **MAY** be asked to check a statement, on a bearer instance, for a loss bound *L* and
an overhead *h*:
- **object *i* is held by *t***: holds when a standing schedule of the instance has an entry for
object *i* that is available at an instant at or before *t*. It is refused when no standing
schedule of the instance has one (`object_not_scheduled`), when it is not available within
the schedule (`availability_not_within_schedule`), and when it is available after *t*
(`availability_after_deadline`).
- **the group is held by *t***: holds when the statement holds for every object of the group,
0 to `leaf_count` − 1, and is refused with the first object's reason otherwise.
A statement that holds says what the publisher planned: a receiver within *L*, hearing every
pass the schedule names, holds the object by *t*, but for a decoding failure no more likely than
`failure_one_in` states. It does not say the passes were sent (the declaration's) or heard (a
reconciliation's).
A publisher's own deadline for an object is its timeliness claim's `by_ms`
([timeliness](timeliness.md) §4.1); held by it, the statement is the publisher's plan against its
own deadline.
## 7. The passes a receiver listens to
A receiver that holds a standing schedule's entry, the instant *t* it is at, its loss bound *L*,
the overhead *h* it decodes at, and, for each source block, the number *n* of distinct encoding
symbols of it that it holds (for `no-code`, of its source symbols), derives the passes to listen
to. The loss bound and overhead are checked as §6.2 checks them, and a holding that does not
give one number for each source block of the object, in the order §5.1 and §5.2 divide it into
them, or that holds more source symbols of a `no-code` block than it has, is `holding_invalid`.
Only passes that start at or after *t* count: a pass under way at *t* has sent symbols the
receiver did not hear. A pass adds, to a block not held, with *m* and *x* as §6.3:
- **`raptorq`, `advance`**: *m* − *x*, none of them sent before;
- **`raptorq`, `repeat`** and **`no-code`**: max(0, *m* − *n* − *x*): of the *m* − *n* ESIs it
lacks, *x* may be the ones it misses again.
The passes are taken in order of their start. While some block is not held, the next pass is
listened to if it adds to a block not held, each such block's *n* growing by what it adds; the
first pass that adds to none ends the plan. The plan is the passes listened to, each with its
start and end; `complete_ms`, the instant the object is held: *t* when it already is, the last
pass's end when the passes listened to suffice, and `null` otherwise; and `listen_ms`, the sum
of their durations: the time the receiver's radio must be on. Outside those passes it **MAY** be
off. Under `repeat` and `no-code` at most one pass adds anything certain within *L*, since after
it a block lacks only symbols the receiver may miss again: a receiver that one pass does not
complete is not certain to be held after any number, and keeps listening, if it does, on its own
judgement of its channel.
## 8. Mappings
A bearer that carries files with FEC states the same parameters in its own description of each
file, for its receivers: on FLUTE (RFC 6726) and the bearers built on it, the FEC Object
Transmission Information of each file in the file delivery table. A schedule restates them,
signed by the publisher, beside the group's receipts, so a relying party with no access to the
bearer can check a promise (§6.4) and a receiver can plan before it tunes (§7). A sink that holds
both compares them; a difference is the bearer's, and the sink reports it rather than choosing
one. The bearer's own repetition (its carousel of descriptions and files) is the schedule's
passes: a pass is one transmission of the object's symbols, whatever the bearer calls it.
## 9. Reasons
The codes this extension adds, each with where it is raised:
| reason | raised at |
|---|---|
| `schedule_not_scheduled` | §4.2 rule 1 |
| `schedule_objects_malformed` | §4.2 rule 2 |
| `schedule_oti_invalid` | §4.2 rule 3.1 |
| `schedule_symbols_invalid` | §4.2 rule 3.2 |
| `schedule_passes_invalid` | §4.2 rule 3.3 |
| `schedule_subject_mismatch` | §4.3 step 1 |
| `schedule_signer_mismatch` | §4.3 step 2 |
| `schedule_leaf_out_of_range` | §4.3 step 3 |
| `schedule_before_group` | §4.3 step 4 |
| `schedule_content_mismatch` | §4.3 step 5 |
| `schedule_length_mismatch` | §4.3 step 5 |
| `schedule_contradicted` | §6.2 step 4 |
| `schedule_on_bidirectional` | §6.2 step 4 |
| `loss_bound_invalid` | §6.2, §7 |
| `overhead_invalid` | §6.2, §7 |
| `holding_invalid` | §7 |
| `object_not_scheduled` | §6.4 |
| `availability_not_within_schedule` | §6.4 |
| `availability_after_deadline` | §6.4 |
A schedule also raises `bearer_contradicted` and `bearer_not_declared` (bearer-receipts §10) at
§6.2 step 4; a group or object the codes of jwp-receipts §3.3; and a claim every code of
jwp-receipts §3.1 steps 1 to 5 and those of step 6 named in §4.3 and bearer-receipts §4.3.
## 10. Conformance
[`live-conformance/carousel/`](../live-conformance/carousel/) holds the corpus, written from
fixed seeds by `wai_carousel_vectors gen` as `vectors.json`. It has:
- **Availability**: RaptorQ objects of one and of several source blocks of two sizes, under
`advance` and `repeat`, at loss bounds of zero and above, reaching a later pass, the last
pass, and none; at each overhead; a Compact No-Code object available at the first pass with
no loss and at none with any; a group of several objects; the same object simulcast on two
instances with different schedules.
- **Statements**: an object and a group held by a deadline, after it, not within the schedule,
and not scheduled.
- **Plans**: a receiver tuning in before the first pass, during one, between passes, holding
part of an object, holding all of it, and one under `repeat` that one pass does not complete.
- **Negative controls**, one for each reason of §9 that a claim or a verdict raises, and the
bounds of §5.1, §5.2 and §5.4 on both sides.
A conforming verifier gives every case the outcome, the reason and everything else the corpus
states. `wai_carousel_vectors verify` and the test `tests/carousel.rs` check that the file
regenerates byte for byte, that `wai-rs` gives every case its outcome, that every reason of §9
appears, that §9 lists exactly the reference's codes, and that Appendix A is the reference's
table. Against an independent implementation of RFC 6330, the test also requires the reference's
*K′* and Partition[] to agree for every block size, and decodes each RaptorQ object a case holds
available at a pass: it encodes the object under the entry's parameters, drops in each pass the
first ⌊*L* · *m* / 1,000,000⌋ symbols of each block (in the first pass, source symbols, so the
decoder must decode), and requires the object back from what is left by that pass's end.
`live-conformance/carousel_verify.py` is the second implementation, written from this text: it
shares no code with `wai-rs`; it verifies groups and objects with the JWP corpus's second
implementation (`jwp-conformance/jwp_verify.py`), and claims through steps 1–5 with the claim
corpus's (`claim-conformance/claim_verify.py`), whose step 4 holds §4.2 with §5.1, §5.2 and
§5.4; it reads Appendix A and §9 from this text, writes §4.3, §5.3, §6 and §7 itself, mutates
copies of the corpus and requires every copy to fail, and drops each of its own checks in turn
and requires the corpus to catch the weakened verifier.
## 11. Patents
The IETF holds disclosures of patents claimed to read on RaptorQ, all from one holder: #1292,
#1511 and #1553 on the drafts of RFC 6330, #1958 on RFC 6330, and #2554 (19 March 2015), which
updates #1958 and has not itself been updated. Its licensing declaration is written out in the
holder's words, not chosen from the disclosure form's options, and gives two terms, by the
product that implements the code:
- **a device that fully implements the specification and implements a wireless wide-area
standard** (the disclosure's example is a UMTS handset or infrastructure equipment): the
holder offers a licence as part of its established terms for such devices, with no royalty
beyond its standard rate for them. The class is **royalty-bearing**, within the licence the
device already needs;
- **a device that fully implements the specification and implements no wireless wide-area
standard**: the holder will not assert the claims against anyone who makes, uses, sells,
imports or offers it, solely for that implementation; it keeps the right to assert them
against a party that asserts a patent against its or its affiliates' products, and against a
product or part that does not fully implement the specification. The class is **royalty-free
non-assertion**, conditional on full implementation and suspended for a party that asserts.
Raptor (RFC 5053), which this revision does not name (§4.1), has disclosures from the same
holder and an earlier one: #615, #618, #702 and #734 on its drafts; #1185 (8 September 2009) on
RFC 5053, which declared a reasonable and non-discriminatory licence with possible royalty or
fee; and #1289, #1508, #1744 and #1957 (6 February 2013), each updating the one before. #1957 has
not been updated, and gives the same two terms as #2554. The holder's general licence statement,
#1176 (20 July 2009), relates to no one document: it offers a non-exclusive licence on reasonable
and non-discriminatory terms, on the basis of reciprocity, for the holder's submissions that an
IETF standard incorporates.
No disclosure relates to RFC 5445 or its draft, nor to RFC 5052, whose division §5.2 applies.
The IETF takes no position on the validity or scope of any disclosed claim (RFC 8179 §4).
Therefore:
- **`no-code` is the default.** Neither RaptorQ nor Raptor is royalty-free for every
implementer: whether a royalty is due turns on the product, which a schedule does not state.
Under SPEC §5 a capability that is not royalty-free is never a default, and the same holds
here: a tool that writes schedules writes `no-code` unless it is set to write `raptorq`.
- **The reference implementation encodes and decodes no symbol** (§1). Its `carousel` module
computes, from the parameters an entry states, the division of §5 and the counts of §6 and §7.
Its test decodes RaptorQ with an independent implementation of RFC 6330 that is a development
dependency of `wai-rs`, which no build of the library carries.
- Whether a product that encodes or decodes RaptorQ or Raptor symbols needs a licence under
these disclosures is a decision for its distributor.
## 12. Security and privacy considerations
- **A schedule is the publisher's word.** Nothing checks that the passes were sent as planned;
a declaration attests transmission and no more, and a relying party that needs to know what
receivers held counts reconciliations (bearer-receipts §6). A schedule that promises more
than was sent is a false statement signed by the group's key, and is evidence of it.
- **A loss bound is the relying party's.** Every statement holds for every pattern of loss
within it (§2). A channel that exceeds it, in a fade or under interference, voids nothing in
the schedule and nothing here predicts how often that happens.
- **It discloses the plan, not the audience.** A schedule names objects, times and code
parameters, which the bearer's own file descriptions already carry to every receiver. A
receiver that plans with it (§7) sends nothing, and a unidirectional bearer's property that
the source learns nothing of its receivers (unidirectional-delivery §2) is kept.
- **Bounded work.** An entry's arithmetic is a few products per source block, and an object has
at most 255 RaptorQ blocks of two sizes or Compact No-Code blocks of two sizes; a schedule's
cost is linear in its entries, whatever the passes' count.
## Appendix A. The values of K′
The column *K′* of RFC 6330 Table 2 (§5.6), in increasing order, restated so that §5.3 can be
applied from this text. The other columns of that table are the code's, and nothing here uses
them.
<!-- k-prime:begin -->
```
10, 12, 18, 20, 26, 30, 32, 36, 42, 46, 48, 49, 55, 60, 62, 69,
75, 84, 88, 91, 95, 97, 101, 114, 119, 125, 127, 138, 140, 149, 153, 160,
166, 168, 179, 181, 185, 187, 200, 213, 217, 225, 236, 242, 248, 257, 263, 269,
280, 295, 301, 305, 324, 337, 341, 347, 355, 362, 368, 372, 380, 385, 393, 405,
418, 428, 434, 447, 453, 466, 478, 486, 491, 497, 511, 526, 532, 542, 549, 557,
563, 573, 580, 588, 594, 600, 606, 619, 633, 640, 648, 666, 675, 685, 693, 703,
718, 728, 736, 747, 759, 778, 792, 802, 811, 821, 835, 845, 860, 870, 891, 903,
913, 926, 938, 950, 963, 977, 989, 1002, 1020, 1032, 1050, 1074, 1085, 1099, 1111, 1136,
1152, 1169, 1183, 1205, 1220, 1236, 1255, 1269, 1285, 1306, 1347, 1361, 1389, 1404, 1420, 1436,
1461, 1477, 1502, 1522, 1539, 1561, 1579, 1600, 1616, 1649, 1673, 1698, 1716, 1734, 1759, 1777,
1800, 1824, 1844, 1863, 1887, 1906, 1926, 1954, 1979, 2005, 2040, 2070, 2103, 2125, 2152, 2195,
2217, 2247, 2278, 2315, 2339, 2367, 2392, 2416, 2447, 2473, 2502, 2528, 2565, 2601, 2640, 2668,
2701, 2737, 2772, 2802, 2831, 2875, 2906, 2938, 2979, 3015, 3056, 3101, 3151, 3186, 3224, 3265,
3299, 3344, 3387, 3423, 3466, 3502, 3539, 3579, 3616, 3658, 3697, 3751, 3792, 3840, 3883, 3924,
3970, 4015, 4069, 4112, 4165, 4207, 4252, 4318, 4365, 4418, 4468, 4513, 4567, 4626, 4681, 4731,
4780, 4838, 4901, 4954, 5008, 5063, 5116, 5172, 5225, 5279, 5334, 5391, 5449, 5506, 5566, 5637,
5694, 5763, 5823, 5896, 5975, 6039, 6102, 6169, 6233, 6296, 6363, 6427, 6518, 6589, 6655, 6730,
6799, 6878, 6956, 7033, 7108, 7185, 7281, 7360, 7445, 7520, 7596, 7675, 7770, 7855, 7935, 8030,
8111, 8194, 8290, 8377, 8474, 8559, 8654, 8744, 8837, 8928, 9019, 9111, 9206, 9303, 9400, 9497,
9601, 9708, 9813, 9916, 10017, 10120, 10241, 10351, 10458, 10567, 10676, 10787, 10899, 11015, 11130, 11245,
11358, 11475, 11590, 11711, 11829, 11956, 12087, 12208, 12333, 12460, 12593, 12726, 12857, 13002, 13143, 13284,
13417, 13558, 13695, 13833, 13974, 14115, 14272, 14415, 14560, 14713, 14862, 15011, 15170, 15325, 15496, 15651,
15808, 15977, 16161, 16336, 16505, 16674, 16851, 17024, 17195, 17376, 17559, 17742, 17929, 18116, 18309, 18503,
18694, 18909, 19126, 19325, 19539, 19740, 19939, 20152, 20355, 20564, 20778, 20988, 21199, 21412, 21629, 21852,
22073, 22301, 22536, 22779, 23010, 23252, 23491, 23730, 23971, 24215, 24476, 24721, 24976, 25230, 25493, 25756,
26022, 26291, 26566, 26838, 27111, 27392, 27682, 27959, 28248, 28548, 28845, 29138, 29434, 29731, 30037, 30346,
30654, 30974, 31285, 31605, 31948, 32272, 32601, 32932, 33282, 33623, 33961, 34302, 34654, 35031, 35395, 35750,
36112, 36479, 36849, 37227, 37606, 37992, 38385, 38787, 39176, 39576, 39980, 40398, 40816, 41226, 41641, 42067,
42490, 42916, 43388, 43840, 44279, 44729, 45183, 45638, 46104, 46574, 47047, 47523, 48007, 48489, 48976, 49470,
49978, 50511, 51017, 51530, 52062, 52586, 53114, 53650, 54188, 54735, 55289, 55843, 56403
```
<!-- k-prime:end -->