# live-conformance/presentation — ad presentation The corpus of [`extensions/ad-presentation.md`](../../extensions/ad-presentation.md) §12: rooms of [live-ads](../../extensions/live-ads.md) breaks under ad policies of version 2 that require presentation claims; each viewer's break-form `wai.video.ssai` receipt, its session derived from the viewer's session key; the `WPC1` claims the viewers' players signed, good ones and a control of each check; the creatives and the attestation issuer a verifier holds; what a verifier states of them; and each accepted room's HLS tags, byte for byte. **Presentation equivalence.** For each vector, a conforming verifier given its `descriptor`, `grants`, `key_log`, `chains`, `policy`, `pt0_ms`, `receipts`, `pods` and `claims`, and the corpus's `creatives` and `issuers` (§9.1), reaches the outcome the vector states, with everything live-ads §9.4 states (see [`../ads/README.md`](../ads/README.md)) and, for an accepted room under a policy that requires claims (§9.4): - `receipt_facts`, each receipt's `presented_spend_micros` beside its `spend_micros`, and its `impressions`, each `slot`, the index of its own `claim` among the claims or `null`, and its `verdict`: `presented` or the reason it does not count; - `claim_facts`, each claim in the order given: its `digest` (`null` when it does not read), its `verdict`, the `receipt` and `slot` it names (from §9.2 step 3 on), and, for an impression's own claim, the `quartile` it reaches, its `run_ms` and its `viewable_ms`; - `spend_micros`, the presented spend of every receipt together. `claim_about` says what each claim is, and is not checked. A verifier that reaches another outcome, reason, place, verdict, fact, spend or tag byte does not conform. The corpus also carries `rfc9578_a2_vector1`: the `pkI`, TokenChallenge and token of RFC 9578 Appendix A.2's first test vector, as printed there. A conforming verifier verifies that token under that key before it reads any token of the corpus. **Provenance.** Generated here: `wai_ad_presentation_vectors gen` writes every file from rooms authored in code, from fixed seeds, as `../ads/` is written. Each session key is SHA-256 of `wai:ad-presentation/corpus/player`, a zero byte and its number (`players` lists their public keys); each media object's content hash SHA-256 of a fixed label and two numbers; each token's nonce SHA-256, and its salt SHA-384, of a fixed label and its number. The issuer's key is the test key RFC 9578 Appendix A.2 publishes; the generator signs the tokens with it. Ed25519 and RSASSA-PSS over a given salt are deterministic, so every file is the same bytes on every machine. The generator asserts that RFC 9578's token verifies, that each vector reaches the outcome and each claim the verdict it was written to have, and that the corpus gives every reason of §11, before it writes. No recorded data. ## Layout - `vectors.json`: `rfc9578_a2_vector1`; `creatives`, each its `objects` (`content_hash`, `duration_ms`); `issuers`, each its `name`, `token_type` and `keys` (DER SubjectPublicKeyInfo, hexadecimal); `players` (informative); and `vectors`. - `NAME.m3u8`: the HLS tags of each accepted room. The rooms, each built as `../ads/`'s are (a producer, a viewer and the decider, whose grant carries the ad budget): - `video_rule`: a 30 s mid-roll under the video rule, five viewers each filled with ad-x (15 s) and ad-y (15 s). Presented: viewer 1's two (one partly out of view, with 3 s at 60%), viewer 3's ad-x, and viewer 7's ad-y measured over the player's area. Controls: `claim_not_viewable` (40% of the pixels; two runs of 1.5 s broken by a pause; a television assumption the video rule does not admit), `claim_duplicate`, `claim_key_unbound`, `claim_asset_mismatch`, `claim_quartile_mismatch`, `bad_signature` (its impression then `claim_absent`), `claim_malformed` (a signed claim that skips with no resumption stated, and a truncated claim), and `claim_no_decision`. - `cross_media_attested`: an out and its in under the cross-media rule, an audible run and an attestation of type 0x0002 from `issuer.example`. Presented: viewer 11's ad-x and viewer 14's two. Controls: `attestation_absent`, `attestation_invalid` (another impression's token; an altered authenticator) and `claim_not_viewable` (muted; 90% of the pixels). - `ceiling_counts_presented`: a budget of 1 minor unit and two receipts each billing 600 000 millionths; one has a claim, so the presented spend is within the ceiling: accepted. - `ceiling_exceeded_by_presented`: the same, both with claims: `funds_exceeded`. - `policy_attestation_without_claim`: `ad_policy_malformed`. ## Running ``` cd ../../wai-rs cargo run --no-default-features --features live_ads --bin wai_ad_presentation_vectors -- verify ../live-conformance/presentation cargo run --no-default-features --features live_ads --bin wai_ad_presentation_vectors -- gen ../live-conformance/presentation # regenerate cargo test --no-default-features --features live_ads --test ad_presentation cd ../live-conformance python3 -I ad_presentation_verify.py presentation ``` `wai_ad_presentation_vectors verify` and `tests/ad_presentation.rs` require every file to regenerate byte for byte, no other file but this one to be there, and `wai-rs` to give every case its outcome; the test also requires §11 to list exactly the reasons the reference reports. `ad_presentation_verify.py` is the second implementation, written from the extension's text and sharing no code with `wai-rs`: it verifies each room, policy and receipt with `live_ads_verify.py`, reads and judges every claim itself, verifies RSASSA-PSS with an implementation of its own, reads §11 from the extension, requires every reason to appear, then mutates copies of the corpus, one defect each, each of which must fail, and drops each of its own checks in turn, each weakened verifier of which the corpus must catch. The browser client's reference producer (`joule-moq-web/web/ads/presentation.test.mjs`) requires `video_rule`'s first claim from an observation sequence. Pass = an exit status of 0 from each.