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
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]>
378 lines
24 KiB
Markdown
378 lines
24 KiB
Markdown
# WAI Extension: Delivery Telemetry
|
||
|
||
> Status: Draft. An **unsigned, advisory** observation about WAI delivery that a sink,
|
||
> edge or origin emits; its mapping onto the keys of CMCD version 2 (CTA-5004-B) and
|
||
> CMSD (CTA-5006), written as RFC 9651 Structured Field Values, with each key's class and
|
||
> what it reveals (§3.4); and the session metrics a log of observations gives, which
|
||
> [telemetry-aggregation](telemetry-aggregation.md) aggregates without the service holding
|
||
> any session's. Reference impl: `wai-rs` —
|
||
> `telemetry::{sf, observation, cmcd, cmsd, qoe}`; the `wai_telemetry` tool; the corpus
|
||
> [`telemetry-conformance/`](../telemetry-conformance/), with a differential against an
|
||
> independent open-source CMCD and CMSD library. Keywords **MUST**, **MUST NOT**,
|
||
> **SHOULD**, **MAY** are RFC 2119/8174.
|
||
|
||
## 1. Status of an observation
|
||
|
||
§1.1 No signature covers an observation. A relying party **MUST NOT** treat one as
|
||
evidence of delivery, presentation, quality or energy. What a session did is attested,
|
||
where it is, by receipts and claims ([jwp-receipts](jwp-receipts.md)), never by
|
||
telemetry.
|
||
|
||
§1.2 An observation **MUST NOT** carry a joule figure, an acquisition class or a quality
|
||
figure. It **MAY** carry content hashes and link hashes as pointers.
|
||
|
||
§1.3 Telemetry binds no receipt to CMCD or CMSD, and no receipt to telemetry.
|
||
|
||
## 2. The observation
|
||
|
||
§2.1 An observation is a JSON object with exactly these members; a member that does not
|
||
apply is `null`. Integers are unsigned and at most 2⁵³ − 1, and a member a report
|
||
carries as an Integer (§3.3: `sn`, `ts_ms`, the object's `d_ms`, `dl_ms`, `ttfb_ms`,
|
||
`ttlb_ms` and `rc`, and the metrics) at most 10¹⁵ − 1, the largest RFC 9651 Integer, so
|
||
every observation can be reported. A string a report carries is printable ASCII.
|
||
|
||
| member | type | meaning |
|
||
|---|---|---|
|
||
| `v` | integer | `1` |
|
||
| `sid` | string | 32 lowercase hexadecimal digits, fresh per session, derived from no identifier (§8) |
|
||
| `sn` | integer | the observation's sequence number in the session |
|
||
| `ts_ms` | integer or `null` | Unix time of the event in milliseconds; required for every event reported in Event mode (§3.1) |
|
||
| `event` | string | `request`, `response`, `start`, `present`, `switch`, `layer-change`, `stall-start`, `stall-end`, `frame-drop`, `capable`, `abandon` or `end` |
|
||
| `cid` | string or `null` | the entry object's content hash (64 lowercase hexadecimal digits), or a deployer's content id of 1–64 letters, digits, `.`, `_` and `-` |
|
||
| `st` | string | stream type: `v` (on demand), `l` (live) or `ll` (low-latency live) |
|
||
| `sf` | string | `o` for WAI objects over the HTTP binding; `h` or `d` for a WAI rendition referenced from HLS or DASH |
|
||
| `object` | object or `null` | for `request` and `response`: the object (§2.2) |
|
||
| `present` | object or `null` | for `present`: `{ unit, layers, first, late_ms, decode_us }`; `first` is `true` only for the session's first presentation; `layers` is at least 1 |
|
||
| `switch` | object or `null` | for `switch`: `{ unit, from, to, reason }`; `from` and `to` are `primary` or `fallback` and differ; `reason` is a §5 term |
|
||
| `layer_change` | object or `null` | for `layer-change`: `{ from, to }`, a change of `layer_cap`; `null` is no cap |
|
||
| `capable` | object or `null` | for `capable`: `{ outcome, reason, classical_floor }` (§2.3) |
|
||
| `cohort` | string or `null` | `control` or `wai`: the arm the content's service assigned the session to |
|
||
| `metrics` | object or `null` | `{ msd_ms, bsa, bsda_ms, dfa }`: media start delay, buffer starvations and their total duration since the session began, and dropped frames since the session began |
|
||
| `claim` | 64 hexadecimal digits or `null` | on `end` only: the link hash of the session's `reconstruct-session` claim ([jwp-receipts](jwp-receipts.md) §2.4.12), where the sink sealed one |
|
||
|
||
§2.2 **The object** has exactly the members `ot`, `url`, `content_hash`, `capability`,
|
||
`rendition`, `layer`, `layers_total`, `layer_cap`, `counted`, `transferred`, `d_ms`,
|
||
`dl_ms`, `ttfb_ms`, `ttlb_ms`, `rc`, `path` and `receipt`, each `null` where it does
|
||
not apply:
|
||
|
||
- `ot` is a CTA-5004-B object type token (`m`, `a`, `v`, `av`, `i`, `c`, `tt`, `k`,
|
||
`o`); `content_hash` the object's content hash and `receipt` a receipt's link hash,
|
||
each 64 lowercase hexadecimal digits; `capability` at most 64 characters;
|
||
`rendition` the `WAI2` rendition index; `layer` and `layers_total` the object's
|
||
stage and its stage set's stage count; `layer_cap` the cap the request asks for;
|
||
`counted` its counted bytes and `transferred` its transferred bytes
|
||
([staged-measurement](staged-measurement.md) §3); `path` `primary` or `fallback`;
|
||
`url` the object's address, at most 2048 characters, holding no `?`, `#`, `@` or `\`
|
||
(§8.2).
|
||
- The request keys `ot`, `d_ms`, `dl_ms` and `layer_cap` are `null` on a `response`;
|
||
the response keys `rc`, `ttfb_ms`, `ttlb_ms` and `url` are `null` on a `request`.
|
||
|
||
§2.3 **A `capable` observation** reports one WAI-arm dispatch outcome: `not-reached`
|
||
(no dispatch decision for a WAI object was reached), `missing-capability`,
|
||
`pin-refused`, `module-refused`, `below-rate` or `capable`. `reason` is SPEC §3.1's pin
|
||
refusal for `pin-refused` (one of the terms §5 lists before `missing-capability`), and
|
||
`null` otherwise. `classical_floor` is the platform's answer for the classical
|
||
rendition's codec string, `supported` or `unsupported`, where the sink asked. The
|
||
outcome comes from WAI's own dispatch: advertised capabilities, pin verification and a
|
||
timed decode. A sink **MUST NOT** derive it from a platform media-capability query,
|
||
which answers only for the platform's own decoders; it reports that answer separately,
|
||
as `classical_floor`. How sessions are assigned to arms, and the shares computed over
|
||
outcomes, are not specified in this revision.
|
||
|
||
§2.4 An observation that breaks §2.1–§2.3 is refused as a whole: a member missing or
|
||
not listed, a value of another type or outside its range, an object on an event that
|
||
has none, or none on one that has one.
|
||
|
||
## 3. CMCD version 2 mapping
|
||
|
||
§3.1 The modes:
|
||
|
||
- a `request` observation is reported in Request mode;
|
||
- every other observation is reported in Event mode, with `ts`: a `response` as an
|
||
event report with `e=rr`, whose response keys (`rc`, `ttfb`, `ttlb`, `url`) are never
|
||
carried in Request mode or in a header shard;
|
||
- a `present` observation with `first: false` is not reported in CMCD.
|
||
|
||
Every report carries `v=2`, `sid`, `sn`, `st` and `sf`, and `cid` where it is not `null`.
|
||
|
||
| observation | CMCD | mode |
|
||
|---|---|---|
|
||
| `sid`, `sn`, `cid`, `st`, `sf` | same keys | every report |
|
||
| `object.ot`, `object.d_ms`, `object.dl_ms` | `ot`, `d`, `dl` | request |
|
||
| `object.rc`, `object.ttfb_ms`, `object.ttlb_ms`, `object.url` | `rc`, `ttfb`, `ttlb`, `url`, with `e=rr` | event |
|
||
| `ts_ms` | `ts` | event |
|
||
| `start` / `end` / `abandon` | `e=ps`, `sta=s` / `e` / `q` | event |
|
||
| `present` with `first: true` | `e=ps`, `sta=p` | event |
|
||
| `stall-start` / `stall-end` | `e=ps`, `sta=r` / `p` | event |
|
||
| `metrics.msd_ms`, `metrics.dfa` | `msd`, `dfa` | any report |
|
||
| `metrics.bsa`, `metrics.bsda_ms` | `bsa`, `bsda`, each an inner list of one Integer | any report |
|
||
| `switch`, `capable`, `layer-change`, `frame-drop` | `e=ce`, `cen` = `"wai-switch"`, `"wai-capable"`, `"wai-layer-change"`, `"wai-frame-drop"` | event |
|
||
|
||
§3.2 An emitter **MUST NOT** put counted bytes, a layer or a capability into `br`, `tb`,
|
||
`pb` or any other bitrate key.
|
||
|
||
§3.3 A report is an RFC 9651 Dictionary: Integers for counts and times, Tokens for
|
||
`st`, `sf`, `ot`, `e` and `sta`, Strings for `sid`, `cid`, `url` and `cen`. Its keys are
|
||
written in bytewise order and without optional whitespace, and a key is written only
|
||
when its value is not `null`. The corpus fixes the output byte for byte.
|
||
|
||
§3.4 **Key classes.** Each key this mapping writes has a class:
|
||
|
||
- `delivery`: what the host serving the request needs to serve it;
|
||
- `measurement`: what is only aggregated afterwards.
|
||
|
||
A class informs what a deployment does with a key (§4.3,
|
||
[telemetry-aggregation](telemetry-aggregation.md) §9); it is not a permission, and no key
|
||
is conditional on anything but the observation's members. A Request-mode report goes to the
|
||
host that serves the object, an Event-mode report to the content's own service (§8.3).
|
||
|
||
| key | class | what it reveals | reported in |
|
||
|---|---|---|---|
|
||
| `v` | delivery | the CMCD version the report is written in | every report |
|
||
| `st` | delivery | whether the session plays on demand, live or low-latency live, which a host may serve differently | every report |
|
||
| `ot` | delivery | the kind of object requested, which a host may schedule or cache by | Request mode |
|
||
| `d` | delivery | the requested object's playback duration, which a host may prefetch by | Request mode |
|
||
| `dl` | delivery | the time until the object is needed: the sink's buffer level, or, for an object no buffer governs, its deadline ([timeliness](timeliness.md) §8.2) | Request mode |
|
||
| `science.transaction.wai-ch` | delivery | the exact object, by content hash, which a content-addressed host serves by | Request mode, `e=rr` |
|
||
| `science.transaction.wai-lc` | delivery | the layer cap the request asks the host to apply: the sink's quality ceiling | Request mode, `wai-layer-change` |
|
||
| `sid` | measurement | that reports belong to one session; it is fresh per session (§8.1), so nothing across sessions | every report |
|
||
| `sn` | measurement | the report's place in its session, so how many came before it | every report |
|
||
| `cid` | measurement | the content the session plays | every report |
|
||
| `sf` | measurement | the delivery format: WAI objects, or a WAI rendition through HLS or DASH | every report |
|
||
| `msd` | measurement | the session's media start delay | any report |
|
||
| `bsa`, `bsda` | measurement | the session's buffer starvations and their duration so far: its network conditions | any report |
|
||
| `dfa` | measurement | the frames dropped so far: the device's decode performance | any report |
|
||
| `ts` | measurement | when the event happened | Event mode |
|
||
| `e`, `sta` | measurement | the event and the player's state | Event mode |
|
||
| `rc`, `ttfb`, `ttlb` | measurement | a response's status and timing: the sink's throughput and network latency | Event mode |
|
||
| `url` | measurement | the address of a response's object | Event mode |
|
||
| `cen` | measurement | which of this mapping's custom events occurred | Event mode |
|
||
| `science.transaction.wai-b`, `science.transaction.wai-tx` | measurement | the bytes counted and transferred for an object | Request mode, `e=rr` |
|
||
| `science.transaction.wai-cap` | measurement | a capability the sink decodes: device-identifying | Request mode, `e=rr` |
|
||
| `science.transaction.wai-ri` | measurement | the rendition chosen: the sink's bandwidth and device class | Request mode, `e=rr` |
|
||
| `science.transaction.wai-l`, `science.transaction.wai-lt` | measurement | how far into a stage set the sink fetches | Request mode, `e=rr` |
|
||
| `science.transaction.wai-p` | measurement | whether the sink fell back to the classical rendition | Request mode, `e=rr`, `wai-switch` |
|
||
| `science.transaction.wai-rcpt` | measurement | a receipt the sink holds, which links the request to its receipt chain | Request mode, `e=rr` |
|
||
| `science.transaction.wai-lcf` | measurement | the previous layer cap | `wai-layer-change` |
|
||
| `science.transaction.wai-coh` | measurement | the experiment arm of the session | every report |
|
||
| `science.transaction.wai-u` | measurement | a unit presented or switched | `sta=p`, `wai-switch` |
|
||
| `science.transaction.wai-pl`, `science.transaction.wai-late`, `science.transaction.wai-dec` | measurement | the layers presented, lateness and decode time: device performance, device-identifying | `sta=p` |
|
||
| `science.transaction.wai-sw` | measurement | why the sink switched | `wai-switch` |
|
||
| `science.transaction.wai-co`, `science.transaction.wai-cr`, `science.transaction.wai-cf` | measurement | the dispatch outcome and the platform's classical-floor answer: device-identifying | `wai-capable` |
|
||
| `science.transaction.wai-clm` | measurement | the session's sealed claim, which links the session to its signed claim | `sta=e` |
|
||
|
||
A key this mapping does not write has no class here.
|
||
|
||
## 4. Custom keys
|
||
|
||
§4.1 Custom keys have the form `science.transaction.wai-<x>`: a lowercase first letter,
|
||
then lowercase letters, digits, `.` and `-`, with an inner hyphen (CTA-5004-B's
|
||
custom-key rule). Every custom key's value is a String, the type CTA-5004-B admits for
|
||
custom keys besides a Token; an integer member is written as its decimal digits.
|
||
|
||
| key | from | report | header shard (Request mode) |
|
||
|---|---|---|---|
|
||
| `science.transaction.wai-b` | `object.counted` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-tx` | `object.transferred` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-ch` | `object.content_hash` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-cap` | `object.capability` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-ri` | `object.rendition` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-l` | `object.layer` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-lt` | `object.layers_total` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-p` | `object.path`, or `switch.to`: `"p"` or `"f"` | request, `e=rr`, `wai-switch` | `CMCD-Object` |
|
||
| `science.transaction.wai-rcpt` | `object.receipt` | request, `e=rr` | `CMCD-Object` |
|
||
| `science.transaction.wai-lc` | `object.layer_cap`, or `layer_change.to` | request, `wai-layer-change` | `CMCD-Request` |
|
||
| `science.transaction.wai-lcf` | `layer_change.from` | `wai-layer-change` | — |
|
||
| `science.transaction.wai-coh` | `cohort` | every report | `CMCD-Session` |
|
||
| `science.transaction.wai-u` | `present.unit`, or `switch.unit` | `sta=p` (first presentation), `wai-switch` | — |
|
||
| `science.transaction.wai-pl`, `-late`, `-dec` | `present.layers`, `present.late_ms`, `present.decode_us` | `sta=p` (first presentation) | — |
|
||
| `science.transaction.wai-sw` | `switch.reason` | `wai-switch` | — |
|
||
| `science.transaction.wai-co`, `-cr`, `-cf` | `capable.outcome`, `capable.reason`, `capable.classical_floor` | `wai-capable` | — |
|
||
| `science.transaction.wai-clm` | `claim` | `sta=e` | — |
|
||
|
||
§4.2 In Request mode the report also goes in header shards: each key to the shard
|
||
CTA-5004-B assigns it (`v`, `sid`, `cid`, `st`, `sf` and `msd` to `CMCD-Session`; `sn`,
|
||
`dl` and `dfa` to `CMCD-Request`; `ot` and `d` to `CMCD-Object`; `bsa` and `bsda` to
|
||
`CMCD-Status`), and each custom key to the shard of §4.1. Each shard is a Dictionary
|
||
written as §3.3 writes a report; a shard with no key is not sent.
|
||
|
||
§4.3 **Delivery-only Request mode.** A sink **MAY** report Request mode delivery-only: a
|
||
Request-mode report then carries the members of its observation whose keys are of the
|
||
delivery class (§3.4) and no other, written as §3.3 writes a report, in the header shards of
|
||
§4.2 when it goes in shards. The measurement-class members are not sent to the host; the
|
||
sink reports them to the content's own service in Event mode, or as the measures of
|
||
[telemetry-aggregation](telemetry-aggregation.md) §3. A reader that checks a report it is
|
||
told is delivery-only refuses one that carries a key not of the delivery class,
|
||
`measurement_key_in_delivery`, naming the first such key in bytewise order.
|
||
|
||
## 5. Switch reasons
|
||
|
||
§5.1 A switch reason is one of:
|
||
|
||
- SPEC §3.1's pin refusals, in the order of its checks: `pin-malformed`,
|
||
`form-not-registered`, `form-unreadable`, `form-required`, `prior-revoked`,
|
||
`prior-not-authorised` (check 5, at a sink that holds a key log), `prior-not-held`,
|
||
`digest-superseded`, `set-malformed`, `part-mismatch`, `set-incomplete`;
|
||
- `missing-capability`;
|
||
- `module-unverified`, `module-revoked`, `trap`, `fuel-exhausted`, `memory-exhausted`,
|
||
`deadline-threshold`, `unit-hash-mismatch`, `budget-exhausted`;
|
||
- `not-held-by-deadline`: the primary was not held by its deadline and its fallback was
|
||
presented ([timeliness](timeliness.md) §5.3, §8.6);
|
||
- `recovered`.
|
||
|
||
A later extension adds its reasons here.
|
||
|
||
## 6. CMSD mapping
|
||
|
||
§6.1 An origin or edge **MAY** describe a WAI object in `CMSD-Static` with `at`, `d`,
|
||
`ht`, `nor`, `nrr`, `ot`, `sf`, `st` and `su`, and the custom keys
|
||
`science.transaction.wai-ch` (its content hash), `-l` and `-lt` (its layer and its
|
||
stage set's stage count) and `-rcpt` (a delivery receipt's link hash), each a String.
|
||
`v` is not written for version 1.
|
||
|
||
§6.2 A deriving node adds `science.transaction.wai-op`, its operation token, as a Token.
|
||
|
||
§6.3 `CMSD-Dynamic` **MAY** state, for each node, `etp`, `rtt`, `mb`, `rd` and `du`, and
|
||
`science.transaction.wai-drop` (a String): the number of objects the node discarded on
|
||
delivery timeout since its previous response to the same session. Each node adds its
|
||
own entry, in order; within an entry the parameters are in bytewise order.
|
||
|
||
§6.4 Keys and parameters are written as §3.3 writes a report: in bytewise order, a key
|
||
only when its value is not `null`, and a Boolean (`su`, `du`) only when true.
|
||
|
||
§6.5 CMSD carries no joule figure. An edge's energy travels in a claim.
|
||
|
||
§6.6 **Reading.** A reader reads `CMSD-Static` as an RFC 9651 Dictionary and `CMSD-Dynamic`
|
||
as a List of Strings with parameters, in the subset §3.3 writes (Integers, Strings, Tokens and
|
||
Booleans; a dictionary member with parameters, or a Decimal, is outside it); a field it cannot
|
||
read so is `cmsd_malformed`. It passes over keys and parameters this section does not name: a
|
||
sender may add its own. A key it names with another type is `cmsd_type`: `at`, `d`, `ht`,
|
||
`etp`, `mb`, `rd` and `rtt` are non-negative Integers; `nor`, `nrr` and each node's server are
|
||
non-empty Strings; `ot`, `sf`, `st` and `science.transaction.wai-op` are Tokens; `su` and
|
||
`du` are Booleans, either value; `science.transaction.wai-ch` and `-rcpt` are Strings of 64
|
||
lowercase hexadecimal digits; `science.transaction.wai-l`, `-lt` and `-drop` are Strings of
|
||
decimal digits, with no leading zero but in `"0"` and at most 15 digits. A `v` other than the
|
||
Integer 1 is `cmsd_version` (a `v` that is not an Integer is `cmsd_type`). A field this section
|
||
writes reads back to the description it was written from.
|
||
|
||
| code | meaning |
|
||
|---|---|
|
||
| `cmsd_malformed` | the field is not a Dictionary or List of §3.3's subset |
|
||
| `cmsd_type` | a key or parameter §6.1 to §6.3 name holds another type or form |
|
||
| `cmsd_version` | the field states a CMSD version other than 1 |
|
||
|
||
## 7. Session metrics
|
||
|
||
§7.1 A **log** is one session's observations in `sn` order: one `sid`, `sn` strictly
|
||
increasing, timestamps never decreasing, and nothing after `end` or `abandon`.
|
||
|
||
§7.2 A log gives, in integer milliseconds and bytes:
|
||
|
||
- `started`: the log has a `start`;
|
||
- `vst_ms`, the video start time: the first presentation's `ts_ms` less the `start`'s,
|
||
`null` without both;
|
||
- `exit_before_start`: an `abandon` before any first presentation;
|
||
- `start_failed`: a session that started, never presented, and ended with `end`;
|
||
- `stalls` and `stall_ms`: the stalls begun after the first presentation, each from its
|
||
`stall-start` to its `stall-end`, or to `end` or `abandon` where it is still open,
|
||
and their total duration;
|
||
- `engaged_ms`: from the first presentation to `end` or `abandon`;
|
||
- `units`: the distinct units presented;
|
||
- `counted`: the counted bytes of every `response`;
|
||
- `claim`: the `end` observation's `claim`.
|
||
|
||
§7.3 These are statements of the emitter, as the observations are (§1.1).
|
||
|
||
## 8. Privacy
|
||
|
||
§8.1 `sid` is fresh per session, and an emitter adds no persistent identifier. Telemetry
|
||
goes to the host that serves an object (Request mode) and to the content's own service
|
||
(Event mode), and, for a measure of [telemetry-aggregation](telemetry-aggregation.md) §3, to
|
||
its task's two aggregators as secret shares, each of which alone reveals nothing about the
|
||
measurement. This extension sets no consent requirement for the service's own mechanics:
|
||
using a distributor's WAI service is the person's agreement to how that service works. Where
|
||
a regime asks for a lawful basis for processing telemetry, the service records it in a
|
||
`lawful-basis` claim ([jwp-receipts](jwp-receipts.md) §2.4.6). What each key reveals, and to
|
||
whom, is §3.4's.
|
||
|
||
§8.2 Neither a URL's query nor a signed URL's token enters an observation. A reader
|
||
refuses an `object.url` that holds a `?`, a `#`, a `@` or a `\`: a query, a fragment,
|
||
user information, or a separator some URL parsers read as `/` and so a way to user
|
||
information past a check for it. It refuses rather than strips them, and a path that
|
||
holds a `@` is refused with the rest. An emitter whose URLs carry a token in their
|
||
path **MUST** report `url` as `null`. `cid`'s syntax (§2.1) admits a content hash or
|
||
a short identifier, and no syntax keeps an address, a token or personal data out of an
|
||
identifier: an emitter **MUST NOT** put an address, a query, a token or personal data
|
||
in `cid`, and reports the content hash where it has no identifier free of them.
|
||
|
||
§8.3 A Request-mode report travels with its request, to the host that serves the object
|
||
and to no other party. Event-mode reports go to the content's own service (§8.1).
|
||
|
||
§8.4 A published aggregate covers at least 50 sessions per cell. A cell with fewer is
|
||
suppressed, not rounded. Where the figures are aggregated under
|
||
[telemetry-aggregation](telemetry-aggregation.md), the service never holds a session's
|
||
figures, and the floor is each aggregator's: a task's minimum batch size is at least 50, and
|
||
an aggregator refuses to release a share of a smaller batch (§4.3, §5.2 there). This
|
||
suppression still applies to what that extension does not aggregate (§9.1 there).
|
||
|
||
## 9. Conformance
|
||
|
||
§9.1 [`telemetry-conformance/`](../telemetry-conformance/) holds:
|
||
|
||
- observations of every event kind, with their expected CMCD reports and header shards
|
||
(`expected/cmcd.json`);
|
||
- observations every reader refuses (`invalid/`);
|
||
- CMSD-Static and CMSD-Dynamic descriptions with their expected fields
|
||
(`expected/cmsd.json`);
|
||
- session logs with their expected metrics (`expected/qoe.json`);
|
||
- CMSD fields to read (`cmsd-read/cases.json`), as §6.1 to §6.3 write them, in another key
|
||
order, with `v=1` and with keys of other senders, and fields each code of §6.6 refuses, with
|
||
their outcomes (`expected/cmsd-read.json`).
|
||
|
||
§9.2 `wai_telemetry verify` requires every expected value byte for byte, and every
|
||
`invalid/` observation refused.
|
||
|
||
§9.3 `cml/differential.mjs` builds each report from this extension's tables, encodes it
|
||
with an independent open-source CMCD and CMSD library at the versions
|
||
`cml/package-lock.json` locks, and requires the expected bytes; reads the
|
||
expected strings back as a dictionary, as a query string and as header shards, and
|
||
requires the report's members; and validates every report, and the Event-mode reports
|
||
together, with no error.
|
||
|
||
§9.4 The delivery-only reports of §4.3, with reports a reader refuses, and the key classes
|
||
of §3.4, are checked in the corpus of
|
||
[telemetry-aggregation](telemetry-aggregation.md) §12.
|
||
|
||
## 10. Wire names
|
||
|
||
§10.1 The custom keys this extension puts in CMCD (CTA-5004-B) and CMSD (CTA-5006) reports,
|
||
each in full:
|
||
|
||
| key | report | section |
|
||
|---|---|---|
|
||
| `science.transaction.wai-b` | CMCD | §4.1 |
|
||
| `science.transaction.wai-tx` | CMCD | §4.1 |
|
||
| `science.transaction.wai-ch` | CMCD, CMSD-Static | §4.1, §6.1 |
|
||
| `science.transaction.wai-cap` | CMCD | §4.1 |
|
||
| `science.transaction.wai-ri` | CMCD | §4.1 |
|
||
| `science.transaction.wai-l` | CMCD, CMSD-Static | §4.1, §6.1 |
|
||
| `science.transaction.wai-lt` | CMCD, CMSD-Static | §4.1, §6.1 |
|
||
| `science.transaction.wai-p` | CMCD | §4.1 |
|
||
| `science.transaction.wai-rcpt` | CMCD, CMSD-Static | §4.1, §6.1 |
|
||
| `science.transaction.wai-lc` | CMCD | §4.1 |
|
||
| `science.transaction.wai-lcf` | CMCD | §4.1 |
|
||
| `science.transaction.wai-coh` | CMCD | §4.1 |
|
||
| `science.transaction.wai-u` | CMCD | §4.1 |
|
||
| `science.transaction.wai-pl` | CMCD | §4.1 |
|
||
| `science.transaction.wai-late` | CMCD | §4.1 |
|
||
| `science.transaction.wai-dec` | CMCD | §4.1 |
|
||
| `science.transaction.wai-sw` | CMCD | §4.1 |
|
||
| `science.transaction.wai-co` | CMCD | §4.1 |
|
||
| `science.transaction.wai-cr` | CMCD | §4.1 |
|
||
| `science.transaction.wai-cf` | CMCD | §4.1 |
|
||
| `science.transaction.wai-clm` | CMCD | §4.1 |
|
||
| `science.transaction.wai-op` | CMSD-Static | §6.2 |
|
||
| `science.transaction.wai-drop` | CMSD-Dynamic | §6.3 |
|
||
|
||
§10.2 The registry lists each as a wire identifier of kind `telemetry-key`
|
||
([REGISTRY](../REGISTRY.md)).
|