Skip to main content

WAI Extension: Delivery Telemetry

Mirrored from the canonical text at commit 0c6a8897 ().

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; and the session metrics a log of observations gives. Reference impl: wai-rs — telemetry::{sf, observation, cmcd, cmsd, qoe}; the wai_telemetry tool; the corpus 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), 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.

membertypemeaning
vinteger1
sidstring32 lowercase hexadecimal digits, fresh per session, derived from no identifier (§8)
snintegerthe observation’s sequence number in the session
ts_msinteger or nullUnix time of the event in milliseconds; required for every event reported in Event mode (§3.1)
eventstringrequest, response, start, present, switch, layer-change, stall-start, stall-end, frame-drop, capable, abandon or end
cidstring or nullthe entry object’s content hash (64 lowercase hexadecimal digits), or a deployer’s content id of 1–64 letters, digits, ., _ and -
ststringstream type: v (on demand), l (live) or ll (low-latency live)
sfstringo for WAI objects over the HTTP binding; h or d for a WAI rendition referenced from HLS or DASH
objectobject or nullfor request and response: the object (§2.2)
presentobject or nullfor present: { unit, layers, first, late_ms, decode_us }; first is true only for the session’s first presentation; layers is at least 1
switchobject or nullfor switch: { unit, from, to, reason }; from and to are primary or fallback and differ; reason is a §5 term
layer_changeobject or nullfor layer-change: { from, to }, a change of layer_cap; null is no cap
capableobject or nullfor capable: { outcome, reason, classical_floor } (§2.3)
cohortstring or nullcontrol or wai: the arm the content’s service assigned the session to
metricsobject 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
claim64 hexadecimal digits or nullon end only: the link hash of the session’s reconstruct-session claim, 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:

§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:

Every report carries v=2, sid, sn, st and sf, and cid where it is not null.

observationCMCDmode
sid, sn, cid, st, sfsame keysevery report
object.ot, object.d_ms, object.dl_msot, d, dlrequest
object.rc, object.ttfb_ms, object.ttlb_ms, object.urlrc, ttfb, ttlb, url, with e=rrevent
ts_mstsevent
start / end / abandone=ps, sta=s / e / qevent
present with first: truee=ps, sta=pevent
stall-start / stall-ende=ps, sta=r / pevent
metrics.msd_ms, metrics.dfamsd, dfaany report
metrics.bsa, metrics.bsda_msbsa, bsda, each an inner list of one Integerany report
switch, capable, layer-change, frame-drope=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.

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.

keyfromreportheader shard (Request mode)
science.transaction.wai-bobject.countedrequest, e=rrCMCD-Object
science.transaction.wai-txobject.transferredrequest, e=rrCMCD-Object
science.transaction.wai-chobject.content_hashrequest, e=rrCMCD-Object
science.transaction.wai-capobject.capabilityrequest, e=rrCMCD-Object
science.transaction.wai-riobject.renditionrequest, e=rrCMCD-Object
science.transaction.wai-lobject.layerrequest, e=rrCMCD-Object
science.transaction.wai-ltobject.layers_totalrequest, e=rrCMCD-Object
science.transaction.wai-pobject.path, or switch.to: "p" or "f"request, e=rr, wai-switchCMCD-Object
science.transaction.wai-rcptobject.receiptrequest, e=rrCMCD-Object
science.transaction.wai-lcobject.layer_cap, or layer_change.torequest, wai-layer-changeCMCD-Request
science.transaction.wai-lcflayer_change.fromwai-layer-change—
science.transaction.wai-cohcohortevery reportCMCD-Session
science.transaction.wai-upresent.unit, or switch.unitsta=p (first presentation), wai-switch—
science.transaction.wai-pl, -late, -decpresent.layers, present.late_ms, present.decode_ussta=p (first presentation)—
science.transaction.wai-swswitch.reasonwai-switch—
science.transaction.wai-co, -cr, -cfcapable.outcome, capable.reason, capable.classical_floorwai-capable—
science.transaction.wai-clmclaimsta=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.

5. Switch reasons

§5.1 A switch reason is one of:

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.

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:

§7.3 These are statements of the emitter, as the observations are (§1.1).

8. Privacy

§8.1 sid is fresh per session. An emitter MUST NOT add a persistent identifier, or send telemetry to a party other than the content’s own service, without the person’s agreement.

§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.

9. Conformance

§9.1 telemetry-conformance/ holds:

§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.