packaging §8.11 registers the record `wai.delivery.marks` (`wai-pack-marks`): a lead's shots (the pieces that follow a cut of wai.pack.scenecut/1, as its stage index flags them), its chapters (titled spans, each beginning at the start of the piece its instant falls in), its break candidates (piece starts a cue began, a chapter begins at or a cut precedes, none inside a clip) and its clips (the run of whole pieces each moment of the policy covers). They are a pure function of the lead's stage index, the effective policy and the chapters a packager is given; the index is held to the policy by digest, so the cuts' thresholds are the policy's, and its moment bits must be §8.1's. A verifier holding the index and the policy derives them again and compares byte for byte (`marks-mismatch`); a policy whose threshold differs from the one the index was cut under is refused (`marks-policy`). They are written as one canonical JSON document, a WebVTT file using chapter title text, EXT-X-DATERANGE tags of three WAI classes after an EXT-X-PROGRAM-DATE-TIME, and DASH EventStreams of the scheme tag:transaction.science,2026:wai/marks, each read back to what it was written from; a reader refuses what its writer would not write (`marks-vtt`, `marks-hls`, `marks-dash`). Texts read: WebVTT CRD 2026-05-20, draft-pantos-hls-rfc8216bis-22 §4.2 and §4.4.5.1, and ISO/IEC 23009-1:2026's MPD schema (PeriodType, EventStreamType, EventType, example G9). The reference packager does not yet write marks into a package. sink-predicate §9 registers `wai.delivery.sink_reel` (`wai-sink-reel`): a source's signed reel predicate naming a programme's marks by digest, each reel a list of candidate clips with the tags a viewer must follow to want each, the regions each is shown in and its caps. A sink assembles each reel from its own location, exposures and interests (the tags its viewer follows, held on the device; unidirectional-delivery §2 names the class), takes in order the candidates its interests want, shown at its location, uncapped and fitting the reel, and presents them in the programme's order. Nothing about the viewer leaves the device; a reel predicate holding a member that would send something is refused `predicate_needs_report`. A candidate may want only tags its clip's record carries (`reel_clip_mismatch`); a sink's log naming a clip with no record in the marks is refused `reel_clip_unknown`, one presenting a clip its interests do not want `reel_not_wanted`. The references are wai-rs's `pack_marks` (feature `pack_marks`) and `sink_predicate::reel` (feature `sink_reel`). The corpora are pack-conformance/marks/ (33 derivations, 18 documents, 26 forms; the indexes of its two fixture cases hold the pieces scenecut/1 cuts the scene-cut corpus's frames into) and live-conformance/sink-reel/ (49 reel predicates, 22 evaluations, 17 logs). marks_verify.py and sink_reel_verify.py, their second implementations, agree on every case; marks_verify.py recomputes the fixtures' cuts from their frames under the policy's thresholds; they fail every mutated copy (11 of 11, 14 of 14) and catch every weakened verifier (24 of 24, 28 of 28). Twenty-three faults planted in the references each fail their tests: a threshold changed in the policy accepted, a fixture's cut moved, a forced piece counted as a shot, a cut inside a clip offered, a cue inside a clip passed over, a chapter begun off its piece, moment bits, the plan digest and a live window unchecked, a quoted title, an unescaped WebVTT title, the HLS reader not held to the writer, DASH events renumbered, a mismatched document verified; and for reels, a reel or a log naming a clip with no record, a sink without interests wanting every clip, the source's order presented, exposures not carried across reels, a report member read, the wrong signing domain, a want the clip's record does not carry, and a reel assembled outside its span. Co-Authored-By: Claude Opus 5.5 <[email protected]>
33 KiB
WAI Extension: Sink-Evaluated Predicates
Status: Draft. Registers the record
wai.delivery.sink_predicate: a source's signed predicate (wai-sink-predicate, §3), the form in which a condition a sink evaluates travels beside a programme, on any bearer and on one with no return path (unidirectional-delivery §2). A predicate 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 sink evaluates it from its own state alone (§4): its location and its record of its own exposures. It gives the programme's verdict as audience-decision §6 has it, and fills each slot itself, taking in order the candidates whose regions hold its location and whose caps its exposures have not reached. Nothing about the device leaves it. A predicate whose evaluation would need a report leaving the device is refused (predicate_needs_report), and a sink's log that presents a candidate whose cap was reached is refused (predicate_cap_breached, §5). No new transport and no new cryptography. The reference implementation is thesink_predicatemodule ofwai-rs(featuresink_predicate); the corpus islive-conformance/sink-predicate/, and its second implementation islive-conformance/sink_predicate_verify.py.This revision adds highlight reels (§9) and registers the record
wai.delivery.sink_reel: a source's signed reel predicate (wai-sink-reel) over the clips of a programme's marks (§8.11 of packaging), each reel a list of candidate clips with the tags a viewer must follow to want each. A sink assembles each reel from its own location, exposures and interests, the tags its viewer follows, held on the device; a sink's log of a reel that names a clip with no record in the marks is refused (reel_clip_unknown). The reference is thereelmodule (featuresink_reel); the corpus islive-conformance/sink-reel/, and its second implementationlive-conformance/sink_reel_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.Texts read for this revision: WAI's own.
1. Scope
In scope: the predicate, its form, digest and signature, and the members by which it would send something away from the device (§3); the sink's state, the programme's verdict, a candidate's regions and caps, a slot's fill and the evaluation (§4); and a sink's log of a slot, checked (§5).
Out of scope: a transport, and how a predicate and the creatives it names reach a sink; how a sink learns where it is; which candidates a source offers, and in which order, which is the source's own; what a slot's filler is; and counting presentations, which impression-aggregates does apart from any predicate. A predicate's evaluation sends nothing, and nothing here requires a sink to report what it presented.
Relationship to the core spec: wai.delivery.sink_predicate is a record (SPEC
§5): a signed record a WAI tool emits and verifies. It names no payload format and is not
dispatchable. It travels beside the programme it is about and is evaluated where the programme is
presented: on the sink.
Relationship to unidirectional-delivery: §2 there states what a
predicate owes: it is a total function of the object and the sink's declared state class, and it
cannot cause a request. This extension is the registered form of such a predicate: the predicate
is the object, state declares its state classes (§3.1), and §4 is the function.
Relationship to audience-decision: a predicate's blackouts are that extension's (§4.2 there), and the programme's verdict is what its §4.3 and §4.6 give at the sink's location, as its §6 has a sink on a bearer with no return path decide it. A decision of its §4 records a verdict reached away from the sink; a predicate travels to a sink that reaches it.
Relationship to live-ads and stitched-presentation: their decisions are made away from the sink, by a decider that receives a request. A predicate's slots are filled where no request is made: on a sink of a linear channel whose breaks reach every sink alike.
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.
- Blackout, listed codes and a session's location: audience-decision §2 and §4.2. Here the session is the sink's.
- Source: an Ed25519 key that signs predicates: the party whose programme and slots they are.
- Sink: the device that presents the programme.
- Slot: a span of the programme, at an instant, that ads fill.
- Candidate: an ad a slot may be filled with.
- Creative digest: ad-presentation §4.
- Exposure: one presentation by the sink of a candidate with a cap, kept on the device as the cap's counter and the instant: one exposure for each cap the candidate has.
3. The predicate
3.1 Members
A predicate is a document of exactly these members:
| member | form |
|---|---|
kind |
"wai-sink-predicate" |
version |
1 |
source |
a key: 64 lowercase hexadecimal digits |
programme |
a token: the programme, as a session class names it (content_id, http-delivery Appendix H) |
start |
a time: from when the predicate holds |
end |
a time: from when it holds nothing |
state |
the state classes it reads (§4.1), strictly ascending by their bytes: "exposures" exactly when a candidate has a cap, and "location" exactly when it has a blackout or a candidate shown other than everywhere |
blackouts |
0 to 256 blackouts (audience-decision §4.2), in strictly ascending order of their ids' bytes |
slots |
0 to 64 slots (§3.2), in strictly ascending order of at, their ids distinct |
sig |
a signature (§3.4) |
3.2 A slot
| member | form |
|---|---|
id |
a token: the slot |
at |
a time, at or after start and before end: when the slot begins |
avail_ms |
an integer from 1 to 3,600,000: the slot's length, in milliseconds |
candidates |
1 to 64 candidates (§3.3), in the order the source prefers them, their ads distinct |
filler |
a token, what the sink shows in the part of the slot its fill leaves, or null for what the stream itself carries there |
3.3 A candidate and its caps
| member | form |
|---|---|
ad |
a token: the ad |
creative |
its creative digest: 64 lowercase hexadecimal digits |
duration_ms |
an integer from 1 to its slot's avail_ms |
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" |
caps |
0 to 8 caps, in strictly ascending order of their counters' bytes |
show and regions are a territory statement's (audience-decision §5.1), for one ad. A cap is
an object of exactly these members:
| member | form |
|---|---|
counter |
a token: what the cap counts, which candidates that share it count together |
limit |
an integer from 1 to 1,000: the most exposures of the counter in a window |
window |
an integer from 1 to 2⁵³ − 1: the window's length, in microseconds |
3.4 Digest and signature
The digest of a predicate is SHA-256 over the canonical form of the predicate without sig,
written as 64 lowercase hexadecimal digits. The signature is Ed25519 by source over
wai:sink-predicate (ASCII) and 0x01, followed by that same canonical form: route-record §5.3's
construction under its own domain, as audience-decision §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.
3.5 Reading and rules
A predicate sends nothing. Its evaluation reads only state the device holds (§4.1). A predicate
that holds, at any depth, a member by which its evaluation would send something away from the
device — report, beacon, callback or uri (somewhere to send to), or household or
account (a count kept across devices, which no device holds unless the others report to it) — is
refused predicate_needs_report, before any other rule of form: one sink would take such a member
as asking it to send, and another would pass over it.
A reader is given a text. It refuses it predicate_malformed when the text holds more than
1,048,576 bytes or is not a document; predicate_needs_report as above; predicate_malformed when
it breaks one of rules 1 to 4; and then predicate_signature_invalid for its signature (§3.4). The
rules, in order:
- Its members are exactly §3.1's, each blackout's audience-decision §4.2's, each slot's §3.2's,
each candidate's and each cap's §3.3's, each of its form.
versionis 1. startis belowend; each slot'satis at or afterstartand belowend; the slots are in strictly ascending order ofat, and theirids are distinct.- The blackouts are in strictly ascending order of their ids, and each blackout's
regionsare as audience-decision §4.2 states; in each slot, theads are distinct and eachduration_msis at most the slot'savail_ms; each candidate'sregionsare as §3.3 states, empty exactly whenshowis"everywhere"; and its caps are in strictly ascending order of their counters. stateis exactly the classes §3.1 gives.
4. Evaluation, on the sink
4.1 The sink's state
A sink's state is its own, held on the device:
- its location: a region code, at the finest it holds, or none (audience-decision §2);
- its exposures: each a counter (a token) and an instant (a time), at most 65,536; or not kept, for a sink that keeps none;
- its sources: the keys whose predicates it evaluates, provisioned on the device out of band, as a trust anchor is (unidirectional-delivery §3).
The location is the state class location and the exposures the class exposures
(unidirectional-delivery §2). A predicate reads no class its state does not name.
4.2 The programme
The sink aggregates its location against the listed codes of the predicate's blackouts
(audience-decision §4.3), and the programme's verdict, the blackouts applied and the programme
shown in place are what audience-decision §4.6 gives at that aggregation: show, withhold or
alternate. Unresolved is not outside: with no location, every blackout applies.
4.3 A candidate's regions
A candidate is shown at the sink's location when:
- its
showis"everywhere"; or - its
showis"only", the sink holds a location, and the candidate'sregionshold it; or - its
showis"except", the sink holds a location, the candidate'sregionsdo not hold it, and the location is not a country of which theregionslist a subdivision.
So a sink with no location is shown only a candidate shown everywhere, and one whose location is a
country of which a candidate lists a subdivision is shown it neither under "only" nor under
"except": it does not say which of its subdivisions holds it, as audience-decision §5.5 calls such
a territory undetermined.
4.4 A candidate's caps
A cap is reached at an instant t when the sink's exposures of its counter at instants e
with e ≤ t < e + window number at least its limit. An exposure at an instant after t
is not counted. A candidate admits at t when it has no cap, or when the sink keeps its
exposures and none of its caps is reached at t. A sink that keeps no exposures cannot honour a
cap, and a candidate with one never admits there.
4.5 A slot's fill
A slot is filled at its at. With the avail not yet taken starting at avail_ms, the candidates
are taken in their order. A candidate is taken when it is shown at the location (§4.3), it
admits at at (§4.4), counting with the sink's exposures those that the candidates taken before it
in the slot added, and its duration_ms is at most the avail not yet taken. A taken candidate adds
one exposure at at for each of its caps' counters, and its duration_ms is taken from the avail.
The slot's fill is the taken candidates' ads, in order, and its rest is the avail not
taken, in milliseconds, in which the slot's filler is shown.
4.6 The evaluation
A sink's evaluation of a predicate's text, in order:
- reads it (§3.5), and refuses with its reason when it does not read;
- requires its
sourceto be among the sink's sources: otherwisepredicate_source_unknown; - gives the programme's verdict (§4.2);
- when the verdict is
show, fills each slot (§4.5) in order ofat, each from the sink's exposures and those the earlier slots' fills added; under any other verdict it fills no slot, and the sink shows what audience-decision §6 says.
It gives the verdict, the blackouts applied and the programme shown in place, and for each slot
filled its id, its fill and its rest.
What it reads and what it sends. The evaluation is a function of the predicate and the sink's
state alone. It MUST NOT cause a request, and the location, the exposures, the verdict and the
fills leave the device nowhere (unidirectional-delivery §2). Two sinks holding the same state reach
the same evaluation. A sink presents each slot's fill and keeps the exposures it adds; one that does
not hold a taken candidate's creative whole shows the slot's filler in its place for its
duration_ms, and keeps no exposure for it.
5. A sink's log, checked
A sink's log of a slot is the ads it presented in it, in order. A log stays on the device,
as the exposures do. It is read where the device itself is examined: by the sink, holding itself
to its predicate before it presents each ad, and by a harness running a sink under test
(conformance-results). A sink MUST NOT present a candidate whose cap
is reached or one not shown at its location, and its log never holds one.
A checker is given a predicate's text, a sink's state as it was before the slot, a slot's id and
a log. In order:
- It evaluates the predicate's programme (§4.6 steps 1 to 3), refusing with its reason, and
fills the slot of that
idalone (§4.5), from the exposures given, when the verdict isshow; a predicate with no slot of thatidis refusedpredicate_fill_mismatch. - For each
adof the log, in order, it requires:- the
adto be a candidate's of the slot, not earlier in the log: otherwisepredicate_fill_mismatch; - the candidate to be shown at the location (§4.3): otherwise
predicate_not_targeted; - the candidate to admit at the slot's
at(§4.4), counting with the exposures given those that the ads before it in the log added: otherwisepredicate_cap_breached.
- the
- It requires the log to be the slot's fill, under the programme's verdict (no fill unless it is
show): otherwisepredicate_fill_mismatch.
A log that passes conforms.
6. Reasons
| reason | raised at |
|---|---|
predicate_malformed |
§3.5 |
predicate_needs_report |
§3.5 |
predicate_signature_invalid |
§3.4, §3.5 |
predicate_source_unknown |
§4.6 step 2, §5 step 1 |
predicate_not_targeted |
§5 step 2 |
predicate_cap_breached |
§5 step 2 |
predicate_fill_mismatch |
§5 steps 1 to 3 |
7. Conformance
live-conformance/sink-predicate/ holds the corpus, written
from fixed seeds by wai_sink_predicate_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:
- predicates (§3.4, §3.5): one with blackouts and capped, targeted slots; one reading no state;
one reading each class alone; one at the bounds of its counts; one written in another order than
its canonical form; each of the six members that would send something, at the top and nested in
a slot, a candidate and a cap;
stateshort of, beyond and out of the order of what the predicate reads; a control of each other rule; and signatures over the wrong bytes (without the domain, under the audience decision's domain, over the text as written, over a body edited after signing), by another key, flipped and under a key of small order; - evaluations (§4): each verdict, with no slot filled when it is not
show; candidates shown and passed over by their regions, with a location in a listed subdivision, in a country of which only subdivisions are listed, outside, and with none; caps reached by the sink's exposures, by an earlier candidate of the same slot and by an earlier slot; exposures at the edges of a window and after the slot; a sink that keeps no exposures; an avail used up; and a source the sink does not hold; - logs (§5): logs that conform, among them an empty one; a log presenting a candidate whose cap
the sink's exposures reached, one presenting two candidates of one counter where its limit is one,
and one presenting a capped candidate on a sink that keeps no exposures, each
predicate_cap_breached; a log presenting a candidate not shown at the location (predicate_not_targeted); and logs that pass over a candidate the fill takes, present an ad that is not a candidate, present the fill out of order, overrun the avail, fill a withheld programme, or name a slot the predicate does not have (predicate_fill_mismatch).
A conforming implementation gives every case its outcome. wai_sink_predicate_vectors verify and
the test tests/sink_predicate.rs check that the file regenerates byte for byte, that wai-rs
gives every case its outcome, and that §6 lists exactly the codes the reference reports.
live-conformance/sink_predicate_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, blackouts, their
aggregation and what follows from them with the audience decision corpus's, and Ed25519 with WAI's
strict rule (claim-conformance/_ed25519.py). It requires every case's outcome and every reason of
§6; that no evaluation depends on the order of the sink's exposures, on exposures of a counter no
cap names, or on the order of a document's members; and that each slot's fill, given as a log
with the state the sink held before that slot, conforms. 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.
8. Security and privacy considerations
- Nothing leaves the device. A sink evaluates a predicate from its own location and exposures (§4), and its evaluation causes no request. The source learns nothing of where a sink is, what it was shown or what it presented. A predicate that names somewhere to send, or a count kept across devices, is refused before it is read (§3.5).
- A cap is the device's own. A cap counts the presentations of one device, kept on it. A count across a household's or an account's devices would need each to report to the others, and a predicate that names one is refused (§3.5).
- What a predicate proves. That the source stated these blackouts and these slots for the programme over the span. It does not prove that a rights holder issued the blackouts, as audience-decision §9 says of a decision.
- Determinism, not enforcement. Two sinks with the same state reach the same evaluation, and a sink's log is checked against it (§5). A sink can state its location or its exposures falsely, and nothing here prevents that (unidirectional-delivery §2).
- Unresolved is not outside. A sink with no location has every blackout applied, and is shown only candidates shown everywhere (§4.2, §4.3). A sink that keeps no exposures is shown no capped candidate (§4.4).
- 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.
9. Highlight reels
A reel predicate (wai-sink-reel) is a source's signed statement, travelling beside a
programme, of the highlight reels a sink may assemble from the clips of the programme's marks
(§8.11 of packaging): the runs of whole pieces each moment of the packaging policy
covers, each with an id and tags. Each reel is a length and a list of candidate clips in the order
the source prefers them, each with the tags a viewer must follow to want it, the regions it is shown
in and its caps. A sink assembles each reel itself, from its own state: its location and its
exposures (§4.1), and its interests, the tags its viewer follows, which the device holds and the
source never learns. Two viewers of one programme are shown two reels, and nothing about either
leaves the device. This section registers the record wai.delivery.sink_reel (SPEC
§5): a signed record a WAI tool emits and verifies, which names no payload format and is not
dispatchable. The reference is the reel module of wai-rs's sink_predicate (feature
sink_reel); the corpus is live-conformance/sink-reel/, and
its second implementation live-conformance/sink_reel_verify.py.
9.1 The reel predicate
A reel predicate is a document of exactly these members:
| member | form |
|---|---|
kind |
"wai-sink-reel" |
version |
1 |
source |
a key |
programme |
a token: the programme |
marks |
the digest of the programme's marks (§8.11.3 of packaging): 64 lowercase hexadecimal digits |
start |
a time: from when it holds |
end |
a time: from when it holds nothing |
state |
the state classes it reads, strictly ascending by their bytes: "exposures" exactly when a candidate has a cap, "interests" exactly when a candidate wants a tag, and "location" exactly when a candidate is shown other than everywhere |
reels |
1 to 16 reels, in strictly ascending order of their ids' bytes |
sig |
a signature |
A reel is an object of exactly the members id, a token; max_ms, an integer from 1 to
3,600,000, the longest the reel runs, in milliseconds; and candidates, 1 to 256 candidates in the
order the source prefers them, their clips distinct.
A candidate is an object of exactly the members clip, a token, the id of a clip of the marks;
duration_ms, an integer from 1 to its reel's max_ms, the clip's length; want, 0 to 16
tokens strictly ascending by their bytes, the tags a viewer must follow one of to want the clip
(none: every viewer wants it); and show, regions and caps, as §3.3's.
Its digest and signature are §3.4's under its own domain: SHA-256 over the canonical form without
sig, and Ed25519 by source over wai:sink-reel (ASCII) and 0x01, followed by that canonical
form, verified strictly. A reader is given a text and refuses it as §3.5 refuses a predicate:
predicate_malformed when the text holds more than 1,048,576 bytes or is not a document;
predicate_needs_report when it holds, at any depth, a member §3.5 names (report, beacon,
callback, uri, household, account); predicate_malformed when its members, each reel's and
each candidate's are not exactly those above, each of its form, version is not 1, start is not
below end, the reels are not in order of their ids, a reel's clips are not distinct, or state is
not exactly the classes above; and then predicate_signature_invalid for its signature.
9.2 The sink's state
A sink's state for a reel predicate is §4.1's (its location, its exposures and its sources) and its
interests: the tags its viewer follows, 0 to 256 tokens held on the device, or not kept,
for a sink that keeps none. The interests are the state class interests
(unidirectional-delivery §2). A sink also reads its own clock: now,
the instant at which it assembles a reel.
9.3 Assembly, on the sink
A candidate is wanted when its want is empty, or when the sink keeps interests and one of the
candidate's want is among them. A sink that keeps no interests wants only a candidate that wants no
tag.
A reel is assembled at now. With the reel not yet taken starting at max_ms, the candidates are
taken in their order. A candidate is taken when it is wanted, it is shown at the location
(§4.3), it admits at now (§4.4), counting with the sink's exposures those that the candidates taken
before it added, and its duration_ms is at most what is left of the reel. A taken candidate adds
one exposure at now for each of its caps' counters, and its duration_ms is taken from the reel.
The reel's clips are the taken candidates' clips in the programme's order: by their start_ms
in the marks, and at one start_ms in the marks' order of clips. They take the sum of their
durations, and leave max_ms less that.
A sink's evaluation of a reel predicate's text at now, given the programme's marks as a text,
in order:
- reads it (§9.1), and refuses with its reason when it does not read;
- requires its
sourceto be among the sink's sources: otherwisepredicate_source_unknown; - requires the marks' digest to be the predicate's
marks, and the marks to read (§8.11.3 of packaging): otherwisereel_marks_mismatch; - requires each candidate's
clip, in order of the reels and of their candidates, to be the id of a clip of the marks (reel_clip_unknown) whoseend_msless itsstart_msis the candidate'sduration_msand whose tags hold every tag the candidate wants (reel_clip_mismatch); - when
nowis at or afterstartand beforeend, assembles each reel in order of the reels, each from the sink's exposures and those the earlier reels added; otherwise it assembles none.
It gives, for each reel assembled, its id, its clips in the order presented, what they take and
what they leave. The sink presents each clip as the run of pieces its record names (first_piece
and pieces, §8.11.3 of packaging), of every component of the package, and keeps the exposures the
reel adds.
What it reads and what it sends. The evaluation is a function of the predicate, the marks, and the sink's state and clock alone. It MUST NOT cause a request, and the interests, the location, the exposures and the reels leave the device nowhere (unidirectional-delivery §2). Two sinks holding the same state at the same instant assemble the same reels.
9.4 A sink's log of a reel, checked
A sink's log of a reel is the clips it presented in it, in order; it stays on the device, as
§5's does. A checker is given a reel predicate's text, the programme's marks, a sink's state as it
was before the reel, now, a reel's id and a log. In order:
- It runs §9.3's steps 1 to 4, refusing with their reason; a predicate with no reel of that
idis refusedpredicate_fill_mismatch. It assembles that reel alone (§9.3), from the exposures given, whennowis in the predicate's span; otherwise the reel is empty. - For each clip of the log, in order, it requires:
- the clip to be the id of a clip of the marks: otherwise
reel_clip_unknown; - the clip to be a candidate's of the reel, not earlier in the log: otherwise
predicate_fill_mismatch; - the candidate to be wanted (§9.3): otherwise
reel_not_wanted; - the candidate to be shown at the location (§4.3): otherwise
predicate_not_targeted; - the candidate to admit at
now(§4.4), counting with the exposures given those the clips before it in the log added: otherwisepredicate_cap_breached.
- the clip to be the id of a clip of the marks: otherwise
- It requires the log to be the reel's clips, in the order presented: otherwise
predicate_fill_mismatch.
A log that passes conforms.
9.5 Reasons
| reason | raised at |
|---|---|
predicate_malformed |
§9.1 |
predicate_needs_report |
§9.1 |
predicate_signature_invalid |
§9.1 |
predicate_source_unknown |
§9.3 step 2, §9.4 step 1 |
reel_marks_mismatch |
§9.3 step 3, §9.4 step 1 |
reel_clip_unknown |
§9.3 step 4, §9.4 steps 1 and 2 |
reel_clip_mismatch |
§9.3 step 4, §9.4 step 1 |
reel_not_wanted |
§9.4 step 2 |
predicate_not_targeted |
§9.4 step 2 |
predicate_cap_breached |
§9.4 step 2 |
predicate_fill_mismatch |
§9.4 steps 1 to 3 |
9.6 Conformance
live-conformance/sink-reel/ holds the corpus, written from fixed
values by wai_sink_reel_vectors gen: vectors.json, which holds every key and each case's inputs
and outcome. The programme's marks are derived by wai-rs's pack_marks from a stage index the
generator writes: eight pieces and six moments, four of them tagged with a team and two with none.
Its keys and regions are as §7's. The cases:
- reel predicates (§9.1): two reels, capped, wanting tags and targeted; one reading no state;
one reading each class alone; one at the bounds of its counts; one written in another order than
its canonical form; each of the six members that would send something, at the top and nested in a
reel, a candidate and a cap;
stateshort of, beyond and out of the order of what it reads; a control of each other rule; and signatures over the wrong bytes (without the domain, under the sink predicate's domain, over the text as written, over a body edited after signing), by another key, flipped and under a key of small order; - evaluations (§9.3): viewers following one team, the other, both, none, a tag no clip carries, and keeping no interests; clips shown and passed over by their regions, at a location and with none; caps reached by the sink's exposures and by an earlier reel's clip, exposures at the edge of a window and after the instant, and a sink that keeps no exposures; instants before the span and at its end; and a source the sink does not hold, other marks, marks that do not read, a clip with no record, a clip of another length and a tag its record does not carry;
- logs (§9.4): logs that conform, among them empty ones; a log naming a clip with no record in
the marks (
reel_clip_unknown); logs presenting a clip the sink's interests do not want, with interests kept and without (reel_not_wanted); a clip not shown at the location; clips whose cap the sink's exposures reached or that a sink keeping no exposures presents; and logs in the source's order rather than the programme's, passing over a clip the reel takes, repeating one, presented outside the span, presenting a clip of the marks that is not the reel's, or naming a reel the predicate does not have.
A conforming implementation gives every case its outcome. wai_sink_reel_vectors verify and the
test tests/sink_reel.rs check that the file regenerates byte for byte, that wai-rs gives every
case its outcome, and that §9.5 lists exactly the codes the reference reports.
live-conformance/sink_reel_verify.py is the second implementation, written from this text: it
shares no code with wai-rs; it reads documents, regions, territories, caps and signatures with
the sink predicate corpus's second implementation, and the marks with the marks corpus's
(pack-conformance/marks_verify.py). It requires every case's outcome and every reason of §9.5;
that no assembly depends on the order of the sink's exposures or interests or of a document's
members; and that each reel it assembles, given as a log, conforms. 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.7 Security and privacy considerations
- Nothing about the viewer leaves the device. A sink's interests, location and exposures, and the reels it assembles, stay on it. Every sink receives the same predicate and the same marks, and the source learns nothing of what a viewer follows, where it is or what it was shown.
- A tag is the packager's, not the viewer's. A candidate wants only tags its clip's record carries (§9.3 step 4), and the record's tags are the packaging policy's moments', so a predicate cannot reach a viewer by a tag no clip states. The interests are matched on the device.
- What a reel predicate proves. That the source stated these reels over these marks for the programme over the span. The marks bind the clips to the lead's stage index by its digest, whose entries name the objects by content hash (packaging §6), so the clips a sink presents are the package's bytes.
- Determinism, not enforcement. Two sinks with the same state at the same instant assemble the same reels, and a sink's log is checked against them (§9.4). A sink can state its interests falsely, and nothing here prevents that, as §8 says of a location.
- Bounded reading. As §8: texts hold at most 1,048,576 bytes, and every count is checked against its bound before it is read.