extensions/sink-predicate.md registers the record `wai.delivery.sink_predicate` (`wai-sink-predicate`): a source's signed predicate travelling beside a programme, the registered form of unidirectional-delivery §2's sink-evaluated predicate. It carries the programme's blackouts (audience-decision §4.2) and its ad slots, each a list of candidate ads in the order the source prefers them, with the regions each is shown in and its frequency caps (a counter, a limit, a window), and declares exactly the state classes it reads (`location`, `exposures`); it is a route-record document signed in its canonical form under `wai:sink-predicate`. A sink evaluates it from its own state alone: the programme's verdict is audience-decision §4.6's at its aggregated location (unresolved, every blackout applied, when it holds none), and when that is `show` it fills each slot itself, taking in order the candidates shown at its location (a country of which a candidate lists only a subdivision is shown neither `only` nor `except`), whose caps its own exposures have not reached in their windows, with those the earlier slots and candidates added, and that fit the avail. A sink that keeps no exposures is shown no capped candidate. The evaluation causes no request and nothing about the device leaves it. A predicate holding, at any depth, a member by which its evaluation would send something away (`report`, `beacon`, `callback`, `uri`) or count across devices (`household`, `account`) is refused `predicate_needs_report`; a sink's log of a slot that presents a candidate whose cap was reached is refused `predicate_cap_breached`, one not shown at the location `predicate_not_targeted`, and any other departure from the fill `predicate_fill_mismatch`. unidirectional-delivery §2 and audience-decision §1 and §6 name it. live-compose §5.10 adds per-session ad tracks: in a squeeze or a double box, a session's sink may show the session's own ad, decided by a stitched-presentation pod-input record of that session, on the session's ad track (owner `ad_` and the session), bound to the composition by an ad-track binding, `WAT1`, signed by the record's signer under `wai:live-compose-ad-track`. A binding that does not match its session's composition is refused `ad_track_mismatch`, naming what differs: a descriptor that is not an ad frame, a record other than the one it names, a shared record or another session's, a record whose frame is not the descriptor's (layout, canvas, corner, window, gap, aspect), or a slot the record does not have; one signed by another key `ad_track_not_permitted`; one out of its bounds `ad_track_invalid`. While a binding is in effect (from `start` for its ad's duration), the session's layout is §5.9's with the track in the ad tile, the program where the room's frame puts it, and the room's ad participant with no tile and no voice. live-compose's §10 table, its descriptor and its receipt are unchanged; its codes for the binding are §5.10.5's. stitched-presentation §4.6 and §6: a composited break whose ad region shows each session its own ad is decided by a record of each session under the room's ad frame, never by a shared record, and the session's claim is that record's one presentation; no record, claim or verification rule changes. The references are the `sink_predicate` module of wai-rs (feature `sink_predicate`) and the `compose_ad_track` module (feature `compose_ad_track`). The corpora are live-conformance/sink-predicate/ (68 predicates, 23 evaluations, 18 logs) and live-conformance/compose-ad-track/ (36 bindings, 17 layouts); sink_predicate_verify.py and compose_ad_track_verify.py are their second implementations, which agree on every case, fail every mutated copy (17 of 17, 13 of 13) and catch every weakened verifier (35 of 35, 21 of 21). Nineteen faults planted in the reference each fail its tests, each matched by a check the second verifier drops: a cap breach (the fill ignoring caps, the log check ignoring them, an exposure a whole window old still counted, a sink that keeps none admitting a capped candidate); a predicate needing a report (the check removed, read only at the top level, the across-device members dropped); a per-session ad track not matching its session's composition (another frame, another session's record, a shared record, a descriptor that is no ad frame, a missing slot, another signer, the track kept at its binding's end); and a signature over the wrong bytes (a predicate's without its domain, under the audience decision's, over the text as written; a binding's without its domain and under the pod-input record's). Co-Authored-By: Claude Opus 5.5 <[email protected]>
2.1 KiB
live-conformance/compose-ad-track — per-session ad tracks
The corpus of extensions/live-compose.md §5.10, in one file,
vectors.json.
Provenance. Generated here by wai_compose_ad_track_vectors gen (wai-rs, feature
compose_ad_track), from Ed25519 keys on seeds of one byte repeated 32 times, the SHA-256 of fixed
labels and constant instants; no input from outside this repository.
keys names every key by its role, as 64 lowercase hexadecimal digits: the room authority that
signs the descriptors, the stitcher that signs the pod-input records and the bindings, other,
and the two players whose session keys name the sessions in sessions. room is the room id.
bindings(§5.10.3) are each adescriptor(WCD1), a pod-inputrecord(WSI1) and abinding(WAT1), as hexadecimal;outcomeisaccepted, with the binding'sdigest, itssession,slot,track,widthandheight, the span fromstarttoend, and the ad region'sshare_bpandregion; orrefusewith itsreason, where it stopped (at:descriptor,recordorbinding) and, forad_track_mismatch, thememberthat differs.layouts(§5.10.4) are each the descriptor'sparams, the room'sentrants(as the live-compose corpus writes them), the session's acceptedbinding(itstrack, picture and span, ornull) and an instantt;outcomeis theorder, thetiles(each naming aprincipalor the session'strack) and thevoices, orrefuseand itsreason.
Everything is synthetic: keys attest nothing. Each binding case states the verdict it was written to have, declared in the generator and never copied from a verifier.
wai_compose_ad_track_vectors verify and tests/compose_ad_track.rs check that the file
regenerates byte for byte and that wai-rs reaches every stated outcome.
../compose_ad_track_verify.py is the second implementation, written from the extension's text,
which also mutates copies of the corpus and drops each of its own checks in turn and requires each
to be caught.