### An ad decision's consent signal and supply chain, bound into what the decider signs

- **The consent signal** ([live-ads](extensions/live-ads.md) §8.6): a break-form `wai.video.ssai` receipt of version 2
  states the consent signal its decision was made under: the Global Privacy Platform string the player gave with its
  request for the asset list, byte for byte, the sections that apply, and a child-directed flag: three of the members
  OpenRTB 2.6 gives an ad request's `Regs`. Its rules hold the string to the URL-safe characters the GPP string's text
  lists, with its header and every section present, and the sections to the string. The section says what each party
  does with the signal: the player gives it as it holds it and never writes or alters a string; the decider states it
  byte for byte, passes it unchanged in every request it makes to fill the break, and marks every such request as
  directed to children when the policy or the request does; no party reads consent from an empty string or age from a
  flag of 0, and a decider or a verifier does not use either to identify a viewer or link one viewer's receipts; and a
  verifier does not decode the string's sections, so a receipt that verifies shows what the decider stated it was given
  and passed on, not that the viewer gave it or that any party honoured it.
- **A GPP string links what carries it** (live-ads §12, [stitched-presentation](extensions/stitched-presentation.md)
  §11): a consent tool makes the string for a viewer, not for one request, and it can stay the same across the viewer's
  sessions and rooms, so a receipt, or a stitched record of one session, whose string is not empty can be linked through
  it to every other that carries the same string, in any room, by whoever holds them. The string is in the signed bytes,
  so it cannot be stripped from a receipt that stays verifiable. The rule against using the string to link binds the
  decider and the verifier only. The cross-room property of a receipt's session holds of receipts that carry no
  string.
- **The supply chain of each impression** (§8.7): the receipt also states, in `supply_chains`, one entry for each
  impression: the `SupplyChain` object (OpenRTB 2.6 §3.2.25 and §3.2.26) of the request whose answer gave the decider
  that impression's candidate, or `null`. A pod's candidates can answer several requests, each with its own chain. A
  chain gives each node's advertising system domain, seller id, payment flag and optional members, with the SHA-256 of
  each system's sellers file (*Sellers.json* 1.0) and of the inventory owner's authorised-sellers file (*ads.txt
  Specification* 1.1, or *app-ads.txt* 1.0 for an app). A verifier that holds those files checks each node against
  them: listed under its seller id in its system's sellers file, and authorised in the owner's file, `DIRECT` for the
  first node of a complete chain and `DIRECT` or `RESELLER` for the others; a part whose file it does not hold is
  stated unchecked. WAI carries the published object and its references, and defines no supply-chain scheme of its
  own.
- **How the files read** (§8.7): an authorised-sellers file by the stated reading of *ads.txt* 1.1 §3.2 to §3.5 (line
  ends, comments, variable records, extension fields, three or four fields). A sellers file is UTF-8 with no byte order
  mark and a JSON text within limits RFC 8259 leaves to a reader: its arrays and objects nest at most 64 deep, the
  members read (`sellers`, `seller_id`, `seller_type`) are not given twice, and the member names and strings read
  escape no lone surrogate. The rest of the file is read by the grammar alone, its numbers never converted, so a number
  of any size reads.
- **Signed.** A receipt of version 2 signs under `wai:video-ssai-break-receipt` 0x02, with the consent signal and the
  chains, in the impressions' order, between its impressions and its signer (§8.4), so a receipt whose string,
  sections, flag or chains changed after signing, or whose chains were moved to other impressions, fails its signature.
  A receipt of version 1 keeps its bytes and its identity, and reads as before.
- **A policy of version 3** (§3.1): the presentation fields of version 2, then an `audience` whose bit 0, **child**,
  marks the room as directed to children. Under it every receipt is of version 2 (`request_terms_absent`), and
  child-directed when the policy says so (`child_directed_unset`) (§9.3 step 13). Step 14 checks each chain against
  the supply files the verifier holds (`supply_file_malformed`, `supply_seller_unlisted`, `supply_seller_unauthorised`),
  and a receipt's own rules gain `consent_invalid` and `supply_chain_invalid` (§8.5 rule 6).
  [ad-presentation](extensions/ad-presentation.md) §8 says that a policy of version 3 carries its presentation fields.
- **The stitched pod-input record** ([stitched-presentation](extensions/stitched-presentation.md) §4.7): `WSI1` of
  version 2 carries the same consent signal after its ads, held to live-ads §8.6's rules, the signer in the decider's
  place; a shared record, which every viewer is shown, carries no viewer's string. A verification states each accepted
  record's signal. `wai_stitched_presentation sign-pod` writes a record of version 2 from a draft's `consent`.
- **The corpora.** [`live-conformance/ads/`](live-conformance/ads/) gains a room under a policy of version 3 whose
  receipts state a GPP string with two ads sold through two complete chains checked against two sellers files and an
  app-ads.txt, and no string with a child-directed request through an incomplete chain left unchecked; a room directed
  to children; a chain two impressions share, authorised by an ads.txt only when each of §8.7's reading rules is
  applied; a sellers file that reads only by the grammar outside what §8.7 reads; four receipts whose string, flag,
  chain or order of chains was changed after signing, each refused `bad_signature`; and a control for each rule of
  §8.2's carriage of version 2, of §8.6 and of §8.7, and for each way a supply file fails to read or to list or
  authorise a node. The supply files are files of the corpus, `supply.*`, read as bytes and kept from line-ending
  conversion; one is not UTF-8.
  [`live-conformance/stitched/`](live-conformance/stitched/) gains `consent`: two records of version 2, one whose GPP
  string was changed after signing (`bad_signature`), a shared record carrying a viewer's string and a record stating
  a section with no string (each `pod_input_malformed`). Every earlier vector keeps its bytes. `live_ads_verify.py`
  and `stitched_presentation_verify.py` read the request terms, the sellers files and the authorised-sellers files
  themselves.
- **Breaking:** `api:rust:wai::live_ads::corpus::generate` and `api:rust:wai::live_ads::corpus::verify` give and take
  each file of the corpus as bytes, since a supply file need not be UTF-8.
- **Breaking:** new members of public structs a literal could build: `api:rust:wai::wai_video_ssai::SsaiBreakReceipt::terms`
  (`None` for a receipt of version 1; `SsaiBreakReceipt::seal` keeps its signature and seals one, and
  `seal_with_terms` seals a receipt of version 2), `api:rust:wai::live_ads::AdPolicy::audience`,
  `api:rust:wai::live_ads::Input::supply_files`, `api:rust:wai::live_ads::ReceiptFacts::terms`,
  `api:rust:wai::stitched_presentation::PodInput::consent` and
  `api:rust:wai::stitched_presentation::RecordFacts::consent`.
- **Breaking:** the variants an exhaustive match needs: `api:rust:wai::wai_video_ssai::BreakReceiptFault::ConsentInvalid`
  and `api:rust:wai::wai_video_ssai::BreakReceiptFault::SupplyChainInvalid`; the reasons live-ads §10 adds,
  `api:rust:wai::live_ads::Reason::ConsentInvalid`, `api:rust:wai::live_ads::Reason::SupplyChainInvalid`,
  `api:rust:wai::live_ads::Reason::RequestTermsAbsent`, `api:rust:wai::live_ads::Reason::ChildDirectedUnset`,
  `api:rust:wai::live_ads::Reason::SupplyFileMalformed`, `api:rust:wai::live_ads::Reason::SupplySellerUnlisted` and
  `api:rust:wai::live_ads::Reason::SupplySellerUnauthorised`; and `api:rust:wai::live_ads::Reason::ALL`, which holds
  them, an array of 27.
