### `wai.delivery.sink_predicate` and per-session ad tracks: targeting and caps evaluated on the sink, and a session's own ad in a room's ad frame - [sink-predicate](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 (everywhere, only in some, everywhere but some) and its frequency caps (a counter, a limit and 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, and nothing about the device leaves it** (§4). The programme's verdict is audience-decision §4.6's at the sink's aggregated location (unresolved when it holds none, and every blackout then applies). When it is `show`, the sink fills each slot itself: a candidate is taken when it is shown at the location (a country of which a candidate lists only a subdivision is shown neither `only` nor `except`), when none of its caps is reached by the sink's own exposures in their windows (with those the earlier slots and candidates added), and when it fits the avail. A sink that keeps no exposures is shown no capped candidate. The evaluation causes no request. - 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 is checked against the evaluation: a candidate presented with a cap reached is refused `predicate_cap_breached`, one not shown at the location `predicate_not_targeted`, and anything else that is not the fill `predicate_fill_mismatch`. - [live-compose](extensions/live-compose.md) §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. A binding is refused `ad_track_mismatch` when the descriptor is not an ad frame, the record is not the one it names, is shared or is another session's, states a frame other than the descriptor's, or has no ad of its slot; `ad_track_not_permitted` when another key signs it; and `ad_track_invalid` out of its bounds. While a binding is in effect, 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 §5.7, §5.8, §7, §10, §11 and §12 say so; its §10 table and its other records are unchanged. - [stitched-presentation](extensions/stitched-presentation.md) §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, and never by a shared record; the session's claim is that record's one presentation. §1 and §11 say so. No record, claim or verification rule changes. - [audience-decision](extensions/audience-decision.md) §1 and §6 and [unidirectional-delivery](extensions/unidirectional-delivery.md) §2 name sink-predicate as the form in which a predicate travels. - 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/` and `live-conformance/compose-ad-track/`, and `sink_predicate_verify.py` and `compose_ad_track_verify.py` are their second implementations.