A falsification moved a squeeze's side band onto the window's side and the corpus still verified: the share is the same area, and no fact stated the rectangles. Each accepted record now states its frame's share and its ad region's rectangles (live-compose §5.9), so wai-rs and stitched_presentation_verify.py must agree on the region, not only its area; the Python verifier gains the matching mutation. Co-Authored-By: Claude Opus 5.5 <[email protected]>
8.8 KiB
live-conformance/stitched — stitched presentation
The corpus of extensions/stitched-presentation.md
§10: streams with ads another party stitched into their segments or served as interstitials;
the manifests the players read (HLS Media Playlists, an asset list, an MPD); the ad servers'
responses (VAST documents and a form-1 wai.video.ssai receipt); the WSI1 pod-input record
each break's signer signed; the WSC1 claims the players signed, good ones and a control of
each check; what a verifier states of them.
Presentation equivalence. For each vector, a conforming verifier given its records and
claims, the files its manifests, responses and receipts name, and the corpus's
creatives, issuers and signers (§7.1), states exactly:
record_facts, each record in the order given: itsdigest(nullwhen it does not read) and itsverdict,acceptedor a reason; for an accepted record,response_checked, itsads(eachslot, itsown_claimsby index,presentations,verdict,quartiles,presented_spend_microsandstated_quartile), itspresented_spend_micros, itsstated_spend_micros, and its frame'sshare_bpand adregion(rectangles[x, y, w, h],nullfor the full picture);claim_facts, each claim in the order given: itsdigest, itsverdict,presentedor a reason, therecordandslotit names (from §7.3 step 4 on), and, for an own claim, thequartileit reaches, itsrun_msand itsviewable_ms;spend, the presented spend by currency.
record_about and claim_about say what each record and claim is, and are not checked. The
files a vector's bound names are documents a record binds by digest and no verifier reads
(a winning bid, a VMAP response); they are here so that anyone recomputes the digests. A
verifier that states another verdict or fact does not conform.
Provenance. Generated here: wai_stitched_presentation vectors gen writes every file from
streams authored in code, from fixed seeds. Each session key is SHA-256 of
wai:stitched-presentation/corpus/player, a zero byte and its number (players lists their
public keys); each signer's key the same with signer (signers 1 and 2 are the trusted ones,
signers; signer 9 is not); 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
attestation issuer's key is the test key RFC 9578 Appendix A.2 publishes, as in
../presentation/. Every playlist, asset list, MPD, VAST document, bid
document and receipt is a fixture written for its case under example domains; none was fetched
from a service. Ed25519, BLAKE3 and RSASSA-PSS over a given salt are deterministic, so every
file is the same bytes on every machine. The generator asserts that each record and claim gets
the verdict it was written to have and that the corpus gives every reason of §9, before it
writes. No recorded data.
Layout
vectors.json:creatives, each itsobjects(content_hash,duration_ms);issuers;signers(Ed25519 public keys, hexadecimal);players(informative); andvectors.NAME.*: each vector's documents:.m3u8Media Playlists,.assets.jsonan asset list,.mpdan MPD,.vast.xmlVAST 4.3 responses,.vmap.xmla VMAP response,.bid.jsona winning bid's document,.receipt.jsona form-1 receipt in its JSON carriage (§4.5).
The vectors:
hls_stitched: two viewers' personalised playlists, each ad under a date range whoseX-AD-IDcarries itsAdServingId; a record per viewer priced from its VASTPricing(CPM 25.00, 18.00 and 30.00 USD). Presented: viewer 1's two ads (the second to its third quartile) and viewer 2's first. Viewer 2's second ad was fetched ahead of the break and never presented:claim_absent, no spend. Record controls:pod_signer_unknown,pod_response_mismatch(a price the response does not give; a universal creative identifier it does not carry),pod_duplicate,pod_input_malformed,bad_signature. Claim controls:claim_duplicate,claim_key_unbound,claim_session_unbound,claim_no_decision,claim_manifest_unknown,claim_marker_absent,stitched_claim_malformed(truncated; a signed skip with no resumption),bad_signature.hls_interstitial: one shared playlist with an interstitial date range, and the asset list a viewer was served; records under the cross-media rule with an audible run and attestation, ad-i1 at a winning bid's price (its document bound by digest), ad-i2 at CPM 20.00. Presented: viewer 11's two, attested on a television. Controls:attestation_absent,attestation_invalid(another presentation's token).squeezeback: a squeeze on a DASH channel, the program in a 1440 × 810 window in the bottom right corner and the ad in the L around it (4375 basis points of the picture), marked by an event whosemessageDatacarries the ad'sAdServingId; one shared record. Presented: viewers 21, 22 (70% of the region in view) and 23 (to the midpoint): three presentations. Controls:claim_frame_mismatch,claim_not_viewable,claim_duplicate,claim_asset_mismatch.double_box: a double box on an HLS channel, its record in EUR at a price the signer states, its VMAP response bound and not read. Presented: viewer 31 over the ad's box, viewer 32 over the player's area.form1_prefetch: a stitcher's own decision sealed in a form-1 receipt whose beacons counted ad-f2 as started when its first segment was fetched ahead of the break; viewer 41 left after ad-f1. Stated: quartiles 5 and 1, 5 000 000 µ-units; presented: ad-f1 alone, 3 000 000. Control:pod_response_mismatch(the same receipt at another price).
Running
cd ../../wai-rs
cargo run --no-default-features --features stitched_presentation --bin wai_stitched_presentation -- vectors verify ../live-conformance/stitched
cargo run --no-default-features --features stitched_presentation --bin wai_stitched_presentation -- vectors gen ../live-conformance/stitched # regenerate
cargo test --no-default-features --features stitched_presentation --test stitched_presentation
cd ../live-conformance
python3 -I stitched_presentation_verify.py stitched
node --test ../../joule-code/joule-code-rs/crates/joule-moq-web/web/ads/stitched.test.mjs
vectors verify and tests/stitched_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 vector its facts; the
test also requires §9 to list exactly the codes the reference adds.
stitched_presentation_verify.py is the second implementation, written from the extension's
text and sharing no code with wai-rs: it reads every manifest, response, record and claim
itself (with the spans' quartile and run and RSASSA-PSS of ad_presentation_verify.py, a
form-1 receipt's leaves of live_ads_verify.py and the ad frame of live_compose_verify.py),
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 requires the corpus's claims from
the corpus's manifests and observation sequences. Pass = an exit status of 0 from each.
The tool's inputs
wai_stitched_presentation verify <bundle.json> (and POST /v1/verify of the service) reads one
JSON object:
| member | value |
|---|---|
records |
the pod-input records, hexadecimal |
claims |
the claims, hexadecimal, at most 2^20 |
manifests |
the manifests' texts, as strings |
responses |
the VAST and VMAP documents' texts, as strings |
receipts |
form-1 receipts in their JSON carriage (§4.5), as objects |
creatives |
as vectors.json's |
issuers |
as vectors.json's |
signers |
the accepted signers' keys, hexadecimal |
and prints record_facts, claim_facts and spend as this corpus states them, with the
capability. wai_stitched_presentation sign-pod <draft.json> --key <seed-file> reads a draft
of a record: the fields of §4.1 by name (carriage, session in hexadecimal or absent for a
shared break, avail_id, avail_ms, response_format, response_file (a path beside the
draft whose SHA-256 is taken) or response (hexadecimal), id_kind, id_attr, currency,
exponent, frame (its fields, or absent for the full picture) and requirement
(require, rule, token_type, issuer)), and ads, each with marker as its fields
(id and start for carriage 1; and index for 2; period, scheme, value and id for
3), ad_id, serving_id, creative_id, registry, creative_hash, duration_ms,
price_micros, price_source and evidence. It refuses a draft that breaks §4.4, and prints
the signed record in hexadecimal.