# WAI Extension: Stitched Presentation > Status: Draft. Registers the record `wai.video.stitched_presentation`: a player's signed > claim, `WSC1`, that it presented one ad another party wrote into the stream, either stitched > into the segments of an HLS or DASH presentation or served as an HLS interstitial, beside the > **pod-input record**, `WSI1`, that the stitcher or a proxy in front of the ad server signs for > each ad decision. A claim names its ad by the **marker** the stream carries for it (an > `EXT-X-DATERANGE` tag, an asset of an interstitial's asset list, or an `Event` of a DASH > `EventStream`) and the ad identity that marker carries, in the manifest whose SHA-256 it > states; it carries ad-presentation's spans of visible and audible play, its viewability rules > and quartile, and its device attestation; and, for an ad shown in a composited frame (a > squeeze or a double box of [live-compose](live-compose.md) §5.9), the share of the picture the > ad's region holds. The pod-input record states the digest of the ad server's response, the > ads it chose with their markers, creatives and prices, the avail, the frame and the > measurement terms. A verifier recomputes, from the claims that verify, each ad's > presentations, the quartiles they reached and the spend that counts; the choice stays the ad > server's. No new transport. The reference implementation is the `stitched_presentation` > module of `wai-rs` (feature `stitched_presentation`); the corpus is > [`live-conformance/stitched/`](../live-conformance/stitched/), and its second implementation > is `live-conformance/stitched_presentation_verify.py`. > Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174. > > Texts read for this revision, each at its source: > > - *Video Ad Serving Template (VAST)* 4.3, December 2022: §3.1 to §3.4.4, §3.4.8, §3.6 to > §3.7.1 and §3.8 to §3.8.1, beside the sections [ad-presentation](ad-presentation.md) read. > - *Server-Side Ad Insertion and OTT Guidance*, August 2021, §1.2, §2 and §3. > - For HLS and DASH, the texts [live-ads](live-ads.md) read, at the revisions it names: > `draft-pantos-hls-rfc8216bis-22` §4.2 (attribute lists), §4.4.5.1 (`EXT-X-DATERANGE`) and > Appendix D (interstitials and the asset list); ISO/IEC 23009-1:2026's MPD schema (its > `EventStream` and `Event`). Nothing here depends on a part of them live-ads did not read. > - RFC 8259 (JSON) and XML 1.0, for the subset of §3.5. > > A section number of one of these texts is that revision's. ## 1. Scope In scope: the marker of an ad in a stream, its body and digest, and how each is read from a playlist, an asset list or an MPD (§3); the pod-input record, its rules and signature, and a form-1 `wai.video.ssai` receipt as its response (§4); the stitched claim, its session, its rules, its signature and its attestation challenge (§5); composited frames (§6); verification: each record's and each claim's verdict, each ad's presentations and quartiles, and the spend that counts, by currency (§7); and the reference producer, the tool and the service (§8). Out of scope: a transport; how a player's session key reaches the signer (§4.6 says what the signer does with it, not how it arrives); the ad decision itself, which stays the ad server's; how a stitcher conditions a creative into segments; the contents of a winning bid's document and of a VMAP document, which a record binds by digest and this revision does not read; the SCTE-35 messages a stream may carry; a billing period, an invoice or a payment, which an operator's system makes from what §7 states; and the detection of invalid traffic, which stays statistical and the measurer's (ad-presentation §13). Relationship to the core spec: `wai.video.stitched_presentation` is a **record** ([SPEC](../SPEC.md) §5): a signed record a WAI tool emits and verifies. It names no payload format and is not dispatchable. Relationship to [ad-presentation](ad-presentation.md): that extension's claim names an impression of a break-form receipt of a room; it puts the stitched form of `wai.video.ssai` out of its scope, since such receipts name no session of a room. This extension brings stitched and interstitial ads into scope with a claim of its own. It takes from ad-presentation, by reference: the creative digest (§4 there); the span and its rules (§5.2, §5.4 rules 4 to 6); the viewability rules, the qualifying run and the quartile (§6); the token, its challenge and its issuer's verifier (§7); and the presentation fields of a policy (§8), here carried in the record. It changes nothing in ad-presentation. Relationship to [live-ads](live-ads.md) and `wai.video.ssai`: a room's breaks keep live-ads' policy and break-form receipts. A stitcher that runs `wai.video.ssai`'s own deterministic decision seals a form-1 receipt as before; a record whose response is that receipt (§4.5) lets a verifier set the receipt's stated quartiles and billable spend beside the ones the players' claims give. Every receipt of either form keeps its bytes. Relationship to [live-compose](live-compose.md): a record's frame (§4.1) is live-compose §5.9's ad frame, and the ad's region and its share are that section's. ## 2. Terms - **Stream**: an HLS presentation or a DASH presentation, live or on demand. - **Stitcher**: the server that writes ads into a stream: into its segments (server-side ad insertion), or as interstitials a player fetches (server-guided ad insertion). - **Ad server**: the party whose response decides which ads fill a break. - **Response**: the ad server's answer, as the signer received it: a VAST document, a VMAP document, or a form-1 `wai.video.ssai` receipt (§4.5). - **Signer**: the key that signs a pod-input record: the stitcher's, or that of a proxy that forwards the stitcher's ad requests to the ad server and their responses back. - **Break**, **avail**: a span of the stream that ads fill, and its duration. - **Manifest**: a document a player reads a marker from: a Media Playlist, an asset list or an MPD (§3). - **Marker**: the fields that place one ad in a stream (§3). - **Ad identity**: the string a marker carries for its ad (§3), 1 to 255 bytes of UTF-8. - **Player**, **session key**, **creative**, **span**, **geometry**, **token**, **issuer**, **basis point**: as in ad-presentation §2. - **Record**: a pod-input record (§4). **Claim**: a stitched claim (§5). - **Presented**: the verdict of a claim that passes every step of §7.3. Integers are little-endian unless this text says otherwise. A digest is SHA-256 (FIPS 180-4), 32 bytes. Ed25519 is RFC 8032's, verified strictly ([SPEC](../SPEC.md) §7 *Signatures*): a key that fails step 1 or 2 is `bad_key`, and a signature that fails a later step is `bad_signature`. A *short* field is a u8 length and that many bytes; a *long* field is a u16 length and that many bytes. A *text* field is a short field of 1 to 255 bytes of UTF-8. ## 3. Markers ### 3.1 The marker, its body and its digest A marker is one of three kinds, by its **carriage**: | carriage | where the stream carries it | its fields | |---|---|---| | 1 | an `EXT-X-DATERANGE` tag of a Media Playlist (§3.2) | the tag's `ID` and `START-DATE` | | 2 | an asset of an HLS interstitial's asset list (§3.3) | the interstitial date range's `ID` and `START-DATE`, and the asset's index in its asset list | | 3 | an `Event` of a DASH `EventStream` (§3.4) | the `id` of its `Period`, the `schemeIdUri` and `value` of its `EventStream`, and its own `id` | A marker's **body** is its fields in that order, each a long field of its bytes as the manifest writes them (an attribute value with its quotes removed; an XML attribute value with its references replaced, §3.5), with an absent `Period` `id` or `EventStream` `value` empty; and, for carriage 2, the asset's index as a u16 after the two long fields. A body of a carriage **reads** when it is exactly those fields, with no byte after them. The **marker digest** is SHA-256 over `wai:stitched-marker` (ASCII) and 0x01, the carriage (one byte) and the body. An HLS date range's `ID` names it within its playlist, and its `START-DATE` is fixed for the `ID` (`draft-pantos-hls-rfc8216bis-22` §4.4.5.1); together they place an ad on the stream's timeline, and stay the same across the reloads of a live playlist. A DASH event is named by its scheme, its value and its `id` within its Period. ### 3.2 Carriage 1: a date range A Media Playlist is read as its lines: its bytes are UTF-8, split at each line feed with a carriage return before it dropped, and its first line is `#EXTM3U`. Each line that begins `#EXT-X-DATERANGE:` is a **date range tag**, and the rest of the line its **attribute list**: `NAME=VALUE` pairs separated by single commas, each name of `A`–`Z`, `0`–`9` and `-` and given once; a value is a quoted string, `"` then bytes other than `"`, CR and LF then `"`, or else one or more bytes other than `"`, `,` and white space. A tag whose list does not read so, or whose `ID` or `START-DATE` is not a quoted string, names no ad. (These are §4.2's rules for an attribute list, as live-ads reads them.) An ad of carriage 1 is a date range tag that carries the attribute the record's `id_attr` names (§4.1). Its marker is the tag's `ID` and `START-DATE`, and its ad identity is that attribute's value: a quoted string's contents, or the value as written. A stitcher writes the ad identity in an attribute of the date range of each ad it stitches; the attribute's name is the stitcher's (a client attribute, `X-` and a name, by §4.4.5.1), and a record names it. ### 3.3 Carriage 2: an interstitial's asset An **interstitial date range** is a date range tag (§3.2) whose `CLASS` is the quoted string `com.apple.hls.interstitial` (Appendix D.2, as live-ads §5.1 writes it). Its asset list is the JSON object (RFC 8259) Appendix D.2 defines: its `ASSETS` member is an array of objects, each with a string member `URI` (live-ads §7.2). An ad of carriage 2 is the asset at index *k* of the asset list a player was served for an interstitial date range. Its marker is the date range's `ID` and `START-DATE` and *k*, and its ad identity is the asset's `URI`. The asset list is the manifest a claim of carriage 2 names (§5.1), since each viewer may be served another one under the same date range; the playlist that carries the date range is held beside it (§7.3 step 6). ### 3.4 Carriage 3: an event An MPD is read as XML by the subset of §3.5. Its root element is `MPD`; each child `Period` of the root, each child `EventStream` of a Period that has a `schemeIdUri`, and each child `Event` of such an EventStream that has an `id` is considered. An ad of carriage 3 is such an Event that carries the attribute the record's `id_attr` names. Its marker is its Period's `id`, its EventStream's `schemeIdUri` and `value`, and its own `id`; its ad identity is the value of that attribute. ### 3.5 The XML subset An XML document (an MPD of §3.4, a VAST document of §7.2) is read over this subset of XML 1.0, and one outside it does not read: - its bytes are UTF-8 with no byte order mark; - before and after its one root element there are only white space, comments and processing instructions (an XML declaration among them); a document type declaration, or any other markup that begins `