wai: an ad decision's consent signal and supply chain, bound into what the decider signs #641
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/ad-consent-supply-chain"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this is
A break-form
wai.video.ssaireceipt of version 2 states the consent signal its ad decision was made under and the supply chain of each impression, and signs both. A live-ads policy of version 3 can mark a room as directed to children. The stitched pod-input record carries the same consent signal.Merge order. Stacked on #633, merge after it. #633 is
wai/one-way-delivery. The two merge cleanly, but together they do not compile without this branch's second commit: one-way's impressions corpus builds astitched_presentation::PodInput, and this branch adds a field to it. Both sit on #632's commit,946f3beda, which moves changelog entries intowai/changes/and the conformance workflow's lists into step files, so #632 merges before either. Until they merge, this pull request's diff also shows their changes.What it carries. Two commits on
wai/one-way-delivery's converted commit,793ed1f2d:d6073e200: the change ofwai/ad-consent-supply-chain(44d5f2264..110c53553) in #632's layout. Its message lists the source commits. The branch's changelog entry is a file ofwai/changes/. Its block ofwai/.gitattributeslines, for the live-ads supply files, sits just before the splat block instead of at the end of the file. A per-directory.gitattributeswas not possible, becauselive_ads_verify.pyandtests/live_ads.rsrefuse any extra file in the corpus's directory. The live-ads and stitched-presentation steps already run these corpora, so the branch adds no step file. Every other file is as the source branch has it.f634e9ab1: the impressions corpus that one-way adds builds its records withconsent: None. Each stays a version-1 record with the bytes it had.What it defines
The consent signal (live-ads §8.6). A receipt of version 2 states:
These are three of the members OpenRTB 2.6 gives an ad request's
Regs. The receipt's rules hold the string to the URL-safe characters the GPP string's text lists, with its header and every section present, and hold the sections to the string. §8.6 says what each party does with the signal:A GPP string links what carries it (live-ads §12, stitched-presentation §11). A consent tool makes the string for a viewer, not for one request, so a receipt or a stitched record whose string is not empty can be linked through it to every other that carries the same string, 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 linking binds the decider and the verifier only.
The supply chain of each impression (§8.7). In
supply_chains, the receipt states one entry for each impression: theSupplyChainobject (OpenRTB 2.6 §3.2.25 and §3.2.26) of the request whose answer gave the decider that impression's candidate, ornull. Each node's entry gives:A verifier that holds those files checks each node against them. The node must be listed under its seller id in its system's sellers file. It must be authorised in the owner's file:
DIRECTfor the first node of a complete chain, andDIRECTorRESELLERfor the others. A part whose file the verifier 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 is read by the stated reading of ads.txt 1.1 §3.2 to §3.5. A sellers file is UTF-8 with no byte order mark, and a JSON text within limits RFC 8259 leaves to a reader:
sellers,seller_id,seller_type) are not given twice;The rest of the file is read by the grammar alone, and its numbers are never converted.
Signed. A receipt of version 2 signs under
wai:video-ssai-break-receipt0x02, 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 fails its signature, and so does one whose chains moved to other impressions. A receipt of version 1 keeps its bytes and its identity, and reads as before.A policy of version 3 (§3.1) adds an
audiencewhose bit 0, child, marks the room as directed to children. Under it every receipt is of version 2 (request_terms_absent), and every receipt is child-directed when the policy says so (child_directed_unset). Step 14 checks each chain against the supply files the verifier holds (supply_file_malformed,supply_seller_unlisted,supply_seller_unauthorised). A receipt's own rules gainconsent_invalidandsupply_chain_invalid.The stitched pod-input record (stitched-presentation §4.7).
WSI1of version 2 carries the same consent signal after its ads, held to live-ads §8.6's rules, with the signer in the decider's place. A shared record, which every viewer is shown, carries no viewer's string.wai_stitched_presentation sign-podwrites a record of version 2 from a draft'sconsent.Breaking:
live_ads::corpus::generateandverifygive and take each file of the corpus as bytes, since a supply file need not be UTF-8. These public structs gain members:SsaiBreakReceipt::terms,AdPolicy::audience,live_ads::Input::supply_files,ReceiptFacts::terms,PodInput::consentandRecordFacts::consent. The fault and reason enums gain the new variants. The entry file names each.The reference and the independent verifiers
The reference. The
wai_video_ssaimodule, its newtermspart, and thelive_adsandstitched_presentationmodules ofwai-rs. Their unit tests andtests/live_ads.rsandtests/stitched_presentation.rscheck that:wai-rsgives every room, record and claim its stated outcome and facts;The corpora.
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. It also gains:bad_signature;live-conformance/stitched/gainsconsent: two records of version 2, one whose string changed after signing (bad_signature), a shared record carrying a viewer's string, and a record stating a section with no string (eachpod_input_malformed). Every earlier vector keeps its bytes.The independent verifiers.
live_ads_verify.pyandstitched_presentation_verify.pyare written from the extensions' text and share no code withwai-rs. They read the request terms, the sellers files and the authorised-sellers files themselves, and require every mutated copy of their corpora to fail.How it was verified
This stack, at
f634e9ab1.scripts/wai-conformance-lists.py selftestandcheck,scripts/wai-conformance-lists-selftest.sh,scripts/check-changelog-fragment.pyagainst main,scripts/changelog-assemble.py --checkandscripts/changelog-fragments-selftest.shall pass. Both rebases, onto946f3bedaand onto one-way's commit, were clean and left every file's change as the conversion first made it.wai/wai-rs,cargo check --locked --no-default-features --testsunder the derivedWAI_FEATURES, and with each ofimpression_aggregate,stitched_presentation,live_ads,receipt_ledger,opportunity_reportandvideo_ssaialone, and with one-way's and this branch's features together;scripts/wai-conformance-lists.py run --only: all four pass, so the impressions corpus regenerates byte for byte and its Python verifier passes;wai_stitched_presentationbinary that the workflow compiles first: its library tests and frame tests,tests/stitched_presentation.rs, the binary'svectors verifyandstitched_presentation_verify.py. All pass. The step's last line, anode --testof joule-moq-web's ad page, was left out: that host has nonode, and neither branch changesjoule-code/.git merge-tree). Merging all of them in forward, reverse and a mixed order gives one tree. On the build host, that tree passes these runs:cargo check --testsunder the derivedWAI_FEATURESand underWAI_PQ_FEATURES;cargo check --testsofquickstart,app; the catalogue's library tests; and thewaibinary's unit tests.On the CI hosts. Results on the CI runners come from this pull request's own CI run. None of the runs above is a CI result.
🤖 Generated with Claude Code