open-standards/wai/extensions/audience-decision.md
Transaction Science 18bdfd276c
Some checks failed
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 14s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 36s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 16s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 41s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 37s
wai-audit collector and player integration / does this change touch it (push) Successful in 36s
wai-fleet service / does this change touch it (push) Successful in 50s
wai-sink-android native sink library / does this change touch it (push) Successful in 35s
wai-ledger service / does this change touch it (push) Successful in 58s
wai-quantum studio and desktop / does this change touch it (push) Successful in 59s
WAI operation catalogue / does this change touch it (push) Successful in 1m5s
wai-sink-swift native sink package / does this change touch it (push) Successful in 26s
wai-key-proxy / does this change touch it (push) Successful in 1m1s
wai-quantum for JavaScript / does this change touch it (push) Successful in 59s
wai-app and Create / wai-app · does this change touch it (push) Successful in 1m13s
WAI Studio / does this change touch it (push) Successful in 42s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 1m18s
wai-fleet service / service · macos (push) Successful in 1m2s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 37s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 1m44s
wai-audit collector and player integration / collector · linux (push) Successful in 2m9s
wai-ledger service / service · macos (push) Successful in 2m24s
wai-key-proxy / proxy · linux (push) Successful in 2m8s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 3m21s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 3m30s
WAI Studio / Studio in WebKit · linux (push) Failing after 51s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m38s
wai-ledger service / service · linux (push) Successful in 4m17s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 3m27s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 6m15s
wai-fleet service / service · linux (push) Successful in 4m51s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 6m33s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 4m53s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 7m8s
wai-quantum for JavaScript / javascript · linux (push) Successful in 6m16s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 9m31s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 9m28s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 9m3s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 9m59s
wai-quantum studio and desktop / studio · browser (push) Successful in 10m26s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 12m55s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 13m18s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 13m10s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 13m21s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 18m47s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 18m25s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 17m24s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 22m34s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 12m33s
wai: sink-evaluated predicates and per-session ad tracks — targeting and frequency caps decided on the sink from its own state, and a session's own ad bound into a room's ad frame
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]>
2026-11-09 21:15:45 -05:00

25 KiB
Raw Permalink Blame History

WAI Extension: Audience Decisions and Territories

Status: Draft. Registers two records, each a route-record document signed by one Ed25519 key. wai.video.audience: a decider's signed audience decision (wai-audience-decision, §4): whether the sessions in one region may be shown a programme over a span, under the blackouts in force for it. Each blackout is named by the id a session class carries (blackouts, http-delivery Appendix H), and states the regions it covers in rung-price §2's region codes and the programme shown in its place, if any. A session's location is aggregated in the session, before it leaves the session, to the one listed region that holds it, to outside, or to unresolved (§4.3). A decision carries that and nothing else of where a session is, and is refused when it carries more (audience_location_not_aggregated) or a region its blackouts do not list (audience_region_not_in_set). Which blackouts apply, the verdict and the programme shown in place follow from the blackouts and the region, and a verifier recomputes them; a session class of the programme carries the blackouts that apply as its own (§4.7). wai.delivery.territory: a publisher's signed territory statement (wai-territory, §5): the regions its content may be shown in, everywhere, only in some, or everywhere but some. A publisher's latest statement stands alone, and one that lapses revives none. A verifier reports, beside the placement of a server key (cache-authority §4.4), whether the receivers' region is within the publisher's territory, and the placement is the same with the statement as without it: a statement names no server, origin or role, and one that does is refused (territory_scopes_serving). No new transport and no new cryptography. The reference implementation is the audience_decision module of wai-rs (feature audience_decision); the corpus is live-conformance/audience/, and its second implementation is live-conformance/audience_decision_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.

Texts read for this revision: WAI's own. SCTE 224 and ISO 3166 were not read: this text takes from SCTE 224 only that an audience is a set of places and a viewing policy what is shown there, and binds none of its elements; of ISO 3166 it binds only the structure of a code (rung-price §2).

1. Scope

In scope: the audience decision, its form, digest and signature, how a session's location is aggregated before it leaves the session, what follows from a decision's blackouts and region, and a decision beside a session class (§4); the territory statement, its form, digest and signature, the statement that stands at an instant, a region against a territory, and the report beside a placement (§5); and a bearer with no return path (§6).

Out of scope: a transport; how a session learns where it is; SCTE 224's documents and how a decider reads them; what a rights holder and a decider agree, which their own contract states; the session class and its receipt (http-delivery §8.6 and Appendix H), which this extension reads and does not change; who may serve what a node holds, which cache-authority §4.3 gives and this extension leaves as it is; the form in which a predicate travels on a bearer with no return path, which sink-predicate registers; and payment.

Relationship to the core spec: wai.video.audience and wai.delivery.territory are records (SPEC §5): signed records a WAI tool emits and verifies. They name no payload format and are not dispatchable. They travel beside the envelopes and playlists they are about and are checked where those are used: a decision where a session is served, a territory statement where a placement is reported.

2. Terms

  • Document, canonical form, time, token, key and signature: as route-record §2. A time is in microseconds.
  • Region code, its country, and holds: rung-price §2, WAI's one definition of them.
  • Decider: an Ed25519 key that signs audience decisions: the service that decides, for a programme, what the sessions in a region are shown.
  • Programme: what a decision is about, named by the token a session class names it by, its content_id (http-delivery Appendix H).
  • Blackout: a restriction on a programme over a span: the regions in which it is not shown, and the programme shown in its place there, if any. Its id is a token: the id a session class lists among its blackouts.
  • Listed codes: of a set of blackouts, every region code any of them lists.
  • Session: one playback of a programme by a client. A session's location is its own state: the region code it holds for where it is, at the finest it holds (a subdivision code or a country code), or none. How a session comes to hold it is out of scope.
  • Publisher: the key that signs a group (cache-authority §2), and signs its territory statements.
  • Placement: cache-authority §4.4's placing of a server key, written as that section writes it.

3. Why these two records

  1. A blackout is contracted per region, and decided per region. A rights holder restricts a programme in regions, and a session is shown it or not by where it is. A decision states the region it decided for, the blackouts in force and what follows, signed, so a party that holds it checks what follows without asking anyone.
  2. A decision needs a region, not a location. Whether a blackout applies is fixed by which of its listed codes holds the session. So a session aggregates its own location to that code before anything leaves it, and a decision carries the code and no more (§4.3). Every session that aggregates to one region gets one decision, as every viewer of a session class gets one playlist (http-delivery §8.6).
  3. One region scheme. Blackouts, a decision's region and a territory are written in rung-price §2's codes and held by its holds, which a lineup's countries, a price list's footprint and a cache's population already use.
  4. Where content may be shown is not who may serve it. A node's operator places a node (cache-authority §4.3), and nothing a publisher signs changes that. A publisher's territory is reported beside a placement, as a key log's confirmation of a claim is reported beside its verdict (cache-authority §4.4), and never in it.

4. The audience decision

4.1 Members

A decision is a document of exactly these members:

member form
kind "wai-audience-decision"
version 1
decider a key: 64 lowercase hexadecimal digits
programme a token: the programme
start a time: from when the decision holds
end a time: from when it holds nothing
blackouts 0 to 256 blackouts (§4.2), in strictly ascending order of their ids' bytes: every blackout in force for the programme over the span
evidence an object of region and resolved (§4.3)
applied 0 to 256 tokens, strictly ascending by their bytes: the ids of the blackouts that apply (§4.6)
verdict "show", "withhold" or "alternate" (§4.6)
alternate a token, the programme shown in place, when verdict is "alternate"; null otherwise
sig a signature (§4.4)

A decision holds for one span. A decider given blackouts that begin or end inside a programme signs one decision for each span between those instants.

4.2 A blackout

member form
id a token: the blackout's id
regions 1 to 8,192 region codes, strictly ascending by their bytes, with no subdivision code whose country it also lists: where the programme is not shown
alternate a token, the programme shown in its place there, or null for none

The regions of one blackout have one encoding, as a footprint does (rung-price §4.5 rule 3). Two blackouts may list the same codes, or one a country and another a subdivision of it.

4.3 The evidence, aggregated in the session

A session's location never leaves the session. What leaves it is the location's aggregation against the listed codes of the blackouts in force, written as evidence:

member form
region a region code, or null
resolved true or false; false only with a region of null

The aggregation of a location s against listed codes L is the first of these that holds:

  1. s is none: unresolved, {"region": null, "resolved": false};
  2. L lists s: {"region": s, "resolved": true};
  3. s is a subdivision code and L lists its country: {"region": the country, "resolved": true};
  4. s is a country code and L lists a subdivision of it: unresolved, since s does not say which of its subdivisions holds the session;
  5. otherwise: outside, {"region": null, "resolved": true}.

So the region, when there is one, is the most specific listed code that holds the location, and a blackout's regions hold that region exactly when they hold the location (rung-price §2 Holds): the aggregation decides what the location would decide, and says no more of it. A session that holds a finer location keeps it. One that holds none, or too coarse a one, is unresolved, and every blackout in force applies to it (§4.6).

The evidence holds nothing else: no coordinates, postal code, address, network address or session's identifier, and no region finer than the one the aggregation gives. A decision whose evidence holds any other member, or a region its listed codes hold without listing it (one finer than the aggregation gives), is refused audience_location_not_aggregated; one whose region its listed codes neither list nor hold is refused audience_region_not_in_set (§4.5).

4.4 Digest and signature

The digest of a decision is SHA-256 over the canonical form of the decision without sig, written as 64 lowercase hexadecimal digits. The signature is Ed25519 by decider over wai:audience-decision (ASCII) and 0x01, followed by that same canonical form: route-record §5.3's construction under its own domain, as rung-price §4.4 is. It is verified strictly, as SPEC §7 Signatures verifies every signature: a key that is not the canonical encoding of a point of large order fails, as does a signature whose scalar is not below the group order.

A signature over any other bytes fails: over the canonical form without the domain, under another record's domain, or over the text as it was written when that is not its canonical form. The canonical form is what is signed, so a decision reads the same whatever the order of its members.

4.5 Reading and rules

A reader is given a text. It refuses it audience_decision_malformed when the text holds more than 1,048,576 bytes, is not a document, or breaks one of rules 1 to 4. A decision that reads is then refused for rule 5, 6 or 7, with that rule's own reason, and then for its signature (audience_decision_signature_invalid, §4.4). The rules, in order:

  1. Its members are exactly §4.1's, and each blackout's exactly §4.2's, each of its form; evidence is an object that holds region and resolved, each of its form. version is 1.
  2. start is below end.
  3. The blackouts are in strictly ascending order of their ids, each blackout's regions are as §4.2 states, and applied is strictly ascending.
  4. resolved is false only with a region of null, and alternate is a token exactly when verdict is "alternate".
  5. evidence holds no member but region and resolved, and the listed codes do not hold a region they do not list (audience_location_not_aggregated).
  6. A region that is not null is a listed code (audience_region_not_in_set).
  7. applied, verdict and alternate are what §4.6 gives (audience_decision_inconsistent).

Rule 5 comes before rule 6: a region the listed codes hold without listing it is a finer location passed on, and a region they neither list nor hold is not a region of the blackouts at all.

4.6 What follows from the blackouts and the region

  • Applied: with resolved and a region, the ids of the blackouts whose regions hold it; outside (resolved and no region), none; unresolved, the id of every blackout.
  • Verdict: "show", with no alternate, when none applies; "alternate", with that programme, when every blackout that applies names one and the same alternate; "withhold", with no alternate, otherwise.

A decision is the same for every session whose location aggregates to its region: a decider MAY sign it once and give it to each of them.

4.7 A decision and a session class

A session class (http-delivery Appendix H, class) of a programme carries the blackouts that apply to its sessions as its blackouts. Given a decision's text and a class, a verifier, in order:

  1. reads the decision (§4.5), and refuses with its reason when it does not read;
  2. reads the class: an object of exactly content_id, entitlement, geo, ad_pod_id (each a string), blackouts (an array of strings) and window (an integer from 0 to 2⁵³ − 1), and refuses it audience_class_malformed otherwise;
  3. requires the class's content_id to be the decision's programme;
  4. requires the class's blackouts, distinct and in ascending order of their bytes as its hash orders them (http-delivery Appendix H), to be applied;
  5. requires the class's geo to be the region's country when the decision has a region, and not a listed code when the decision is outside, since a listed country would hold every session in it. An unresolved decision requires nothing of geo.

A class that fails step 3, 4 or 5 is refused audience_class_mismatch, naming the first member that differs: content_id, blackouts or geo. One that passes is consistent with the decision, and the verifier states its session_class_hash, as Appendix H computes it, by which a playlist receipt of that class names it.

5. The territory statement

5.1 Members

A territory statement is a document of exactly these members:

member form
kind "wai-territory"
version 1
publisher a key: the publisher
issued a time: from when it states the territory
expires a time: from when it states nothing
show "everywhere", "only" or "except": shown everywhere, only in regions, or everywhere but in regions
regions 0 to 8,192 region codes, strictly ascending by their bytes, with no subdivision code whose country it also lists; none exactly when show is "everywhere"
sig a signature (§5.2)

show and regions are a lineup's geo and countries (channel-lineup §6.2), for all of a publisher's content and in region codes.

5.2 Digest and signature

The digest is SHA-256 over the canonical form of the statement without sig. The signature is Ed25519 by publisher over wai:territory (ASCII) and 0x01, followed by that same canonical form, verified strictly as a decision's is (§4.4); a signature over any other bytes fails.

5.3 Reading and rules

A statement names no server. Who may serve what a node holds is given by the node's operator's origin (cache-authority §4.3), and a territory statement changes none of it. A statement that holds a member by which it would name who serves — servers or nodes (keys), origins (key logs), roles or may_sign (authorities, as a key log writes them) — is refused territory_scopes_serving, before any other rule of form: one reader would take such a member as scoping the servers it places, and another would pass over it.

A reader is given a text. It refuses it territory_malformed when the text holds more than 1,048,576 bytes or is not a document; territory_scopes_serving as above; territory_malformed when it breaks one of rules 1 to 3; and then territory_signature_invalid for its signature (§5.2). The rules, in order:

  1. Its members are exactly §5.1's, each of its form. version is 1.
  2. issued is below expires.
  3. regions are as §5.1 states, and empty exactly when show is "everywhere".

5.4 The standing statement

Given texts, a publisher and an instant t (a time), the publisher's statements are the texts that read (§5.3) and whose publisher is that key; a text that does not read is passed over. Of the publisher's statements whose issued is at or before t, the first of these that holds:

  1. there are none: no statement stands (territory_not_stated);
  2. two that differ (by their digests) share the latest issued: none stands (territory_contradicted), and no earlier one revives;
  3. the latest's expires is at or before t: none stands (territory_lapsed), and no earlier one revives;
  4. otherwise the latest stands.

Two texts of one body under two signatures are one statement, with one digest. A publisher's latest statement replaces every earlier one, as a seller's latest price list does (rung-price §5).

5.5 A region against a territory

Of a standing statement and the region a relying party states for the receivers (a region code, or none when it states none), the territory is:

  • within when show is "everywhere";
  • otherwise undetermined when no region is stated;
  • for "only": within when regions hold the region; undetermined when the region is a country of which regions list a subdivision; outside otherwise;
  • for "except": outside when regions hold the region; undetermined when the region is a country of which regions list a subdivision; within otherwise.

It is written within statement=<digest>, outside statement=<digest> or undetermined statement=<digest>, and with no standing statement unstated reason=<code>, the code of §5.4. An unstated territory is reported as unstated, never as within.

5.6 Beside a placement

Given a server key, an instant at_ms and the heads its relying party names, as cache-authority §4.4 is, and a publisher, the receivers' region and territory statements, a verifier reports two lines: the placement, computed by cache-authority §4.4 from the key, the instant and the heads alone, and the territory (§5.5) of the publisher's statement standing at at_ms × 1000.

The placement is the same whatever statements are given and whatever territory is reported beside it: an outside territory refuses no key, and a within territory confirms none. cache-authority §4.3 and §4.4 are unchanged. What a relying party does with a placement beside an outside territory is its own: a payer that pays only for service within a publisher's territory says so in its own terms.

6. No return path

On a bearer with no return path (unidirectional-delivery §2), every sink receives every byte and no decision is made away from it. The blackouts in force are then a sink-evaluated predicate of the programme and the sink's location: the sink aggregates its location against their listed codes (§4.3) and presents what §4.6 gives, with the programme shown in place when it holds it. It causes no request in doing so, and its location and its verdict leave the device nowhere (unidirectional-delivery §2). Two sinks holding the same blackouts and the same location reach the same verdict. There is then no decision to sign: a decision of §4 records one made away from the sink. The blackouts travel to the sink in a predicate of sink-predicate, whose blackouts are §4.2's and whose verdict is §4.6's at the sink's aggregated location (sink-predicate §4.2).

7. Reasons

reason raised at
audience_decision_malformed §4.5 rules 1 to 4, §4.7 step 1
audience_location_not_aggregated §4.3, §4.5 rule 5
audience_region_not_in_set §4.3, §4.5 rule 6
audience_decision_inconsistent §4.5 rule 7
audience_decision_signature_invalid §4.4, §4.5
audience_class_malformed §4.7 step 2
audience_class_mismatch §4.7 steps 3 to 5
territory_malformed §5.3
territory_scopes_serving §5.3
territory_signature_invalid §5.2, §5.3
territory_not_stated §5.4 step 1
territory_contradicted §5.4 step 2
territory_lapsed §5.4 step 3

8. Conformance

live-conformance/audience/ holds the corpus, written from fixed seeds by wai_audience_decision_vectors gen: vectors.json, which holds every key and each case's inputs and outcome. Every key is Ed25519 from a seed of one byte repeated 32 times and attests nothing, and every region is an ISO 3166-1 user-assigned code or a subdivision of one, which names no place. The cases:

  • aggregations (§4.3): locations aggregated against the listed codes of blackouts: a listed subdivision, a subdivision of a listed country, a listed country, a country of which only subdivisions are listed, a subdivision beside a listed one, one outside, and none, with and without blackouts;
  • decisions (§4.4 to §4.6): one for each verdict, outside, unresolved, under no blackouts, under two alternates that differ, and one written in another order than its canonical form; and a control of each rule of §4.5: a text that is not a document, each member out of form, each order, a coordinate, a postal code and a session's identifier in the evidence, a region finer than the aggregation gives, a region the blackouts neither list nor hold, each of applied, verdict and alternate other than §4.6 gives, and signatures over the wrong bytes (without the domain, under the territory domain, over the text as written, over a body edited after signing), by another key, flipped and under a key of small order;
  • classes (§4.7): classes consistent with a decision of each verdict, with blackouts written out of order and twice, and a control of each step;
  • statements (§5.2, §5.3): one of each show, one written out of canonical order, a control of each rule, each of the five members that would name who serves, and signatures over the wrong bytes, by another key, flipped and under a key of small order;
  • territories (§5.4, §5.5): each territory of each show, a later statement replacing an earlier one in either order, one body under two signatures, a text that does not read passed over, statements at their bounds, one lapsed, two contradicting, and none;
  • placements (§5.6): each of cache-authority §4.4's placements beside a territory, a confirmed key beside an outside territory, and a statement that names a server passed over.

A conforming implementation gives every case its outcome. wai_audience_decision_vectors verify and the test tests/audience_decision.rs check that the file regenerates byte for byte, that wai-rs gives every case its outcome, and that §7 lists exactly the codes the reference reports. live-conformance/audience_decision_verify.py is the second implementation, written from this text: it shares no code with wai-rs; it reads documents and their canonical form with the route record corpus's second implementation, region codes with the rung price corpus's, placements with the cache authority corpus's, Ed25519 with WAI's strict rule (claim-conformance/_ed25519.py) and BLAKE3 with claim-conformance/_blake3.py. It requires every case's outcome and every reason of §7; that a decision aggregated from a location decides what the location decides; that no placement changes when its statements are removed; and that no outcome depends on the order of a document's members or of the statements given. It then mutates copies of the corpus and requires every copy to fail, and drops each of its own checks in turn and requires the corpus to catch the weakened verifier.

9. Security and privacy considerations

  • Location stays in the session. A session's location is read in the session and aggregated there (§4.3). A decision holds a region the blackouts list, outside or unresolved, and a reader refuses one that holds more. Every session that aggregates to one region is given one decision, so a decision names no session.
  • What a decision proves. That the decider stated these blackouts for the programme over the span, and what follows from them for the region. It does not prove that a rights holder issued those blackouts: a rights holder checks the set against the restrictions it issued. Nor does it prove where a session was: the region is the session's word, aggregated from its own state.
  • Unresolved is not outside. A session whose location does not decide the blackouts is unresolved, and every blackout in force applies to it; it is never read as outside.
  • What a territory statement proves. That the publisher stated where its content may be shown from issued to expires. It confirms no server and refuses none, and an unstated territory is reported as unstated, never as within.
  • Bounded reading. Texts hold at most 1,048,576 bytes, documents nest at most 64 deep, and every integer is checked against its bound before any arithmetic.