wai: the opportunity report and the statement check (wai.delivery.opportunity) #541
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/fast-statement-check"
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?
Stacked on #539 (
wai/fast-revenue-share, the revenue share). This branch was made from #539's branch and has its latest commit merged in. Until #539 merges, the diff against main includes #539's commits. When #539 merges,origin/maingets merged into this branch (no rebase).What this adds
wai.delivery.opportunity(wai/extensions/opportunity-report.md) is a new extension with its own text. It is not a set of sections added to revenue-share, for three reasons. A report rests on records the statement never reads: a room's cues, and the SCTE 35 sections those cues carry. A report needs no invoice, so an owner whose platform signs nothing can still use it. And #539's text and records keep their bytes.The opportunity report,
WOR1, covers one party of a revenue-share contract over one period. It states the ad breaks that aired in the programmes of the splits that party shares in. Breaks come from two places:t0 + t. When the opening cue is of form 1, its SCTE 35 section is read (§5) and held to the cue's summary.adentries of the signed program-as-run that no cued break starts within. An entry aired in two windows counts once.Each break is attributed by its start, as revenue-share §6 attributes an impression. The report has one line per split and class (cued, scheduled), each giving breaks,
break_ms, slots, unslotted and the party'sppm. Each line carries a citation digest of its cues (kind 12), the policy when slots come from it (kind 13) and its runs (kind 10). The report is signed by its issuer (the owner, the operator or an auditor), and every figure is recomputed.The reported statement is a platform-neutral JSON form (§9.1) and CSV form (RFC 4180, §9.2). Each gives the channel, the period, the currency, a basis (
grossorshare), impressions and revenue as an integer amount, and optionally figures per day and per programme. It is an input and never evidence: a check names it by the SHA-256 of its bytes.The statement check,
WCK1. It has one line for the period, one per day and one per programme. Each line gives:fill_ppm= ⌊impressions × 10⁶ / slots⌋;revenue_per_slot= ⌊revenue / slots⌋.Arithmetic is in integers; a quotient too large for its field is held at 2⁶⁴ − 1.
The flags:
unproved: impressions reported where no break aired;aboveandbelow: the line's fill is outside [floor, ceiling] × the period's own rate. The check states its bounds; the defaults are 500000 and 2000000 ppm;impressions_above_signed,impressions_below_signed,revenue_above_signed,revenue_below_signed: when #539's signed statement for the same contract, party and period is given, its impressions and revenue (the gross sum, or the party's total) sit beside the reported figures on the period line.Operations, under the agent rules:
opportunity.create:wai opportunity create;opportunity.verify:wai opportunity verify, which takes a report's document or a check's;statement.check:wai statement check, which reads CSV for a file named.csv.All three need the feature
opportunity_report(=revenue_share).ops.json, Studio'sactions.generated.jsand the registry export were regenerated, not hand-merged.wai-rs: the module
opportunity_reportwith the submodulessection(the SCTE 35 subset reader and the corpus's section writer),reportedandcorpus; the binwai_opportunity_vectors; the testtests/opportunity_report.rs.Conformance:
live-conformance/opportunity/(50 vectors, 11 accepted) and the independentopportunity_report_verify.py.The rest: the CI step in
wai-conformance.ymland thecli_opsrun inwai-catalogue.yml; entries in REGISTRY.md (the record, and magicsWOR1§7.1 andWCK1§10.1;WSC1was taken), the registry export, the vocabulary, SPEC §5 and CHANGELOG. All my additions to shared files sit in their own blocks.Design decisions
The cues are a room's cues. The opportunity report reuses live-ads' verification of a room (grants, chains, the schedule rules), so the trust root is the room the contract already names. No cue signer is added to
WRC1, whose bytes stay the same. An injector's cues (cue-injection) are cues of the room. The report does not translate theirWIJ1records again; cue-injection §8 does that.What a section states (§5). The report reads the CRC, the header,
splice_insert(),time_signal()andsplice_null(), and theCUEIsegmentation descriptors. From them it takes three things:sub_segments_expectedof the first placement-opportunity start descriptor (0x34 or 0x36);break_duration, or the opening descriptor'ssegmentation_duration;splice_event_id, or the opening descriptor'ssegmentation_event_id.A section that does not read is
cue_section_invalid. If the summary contradicts the section (a cancel or a return in the section, another id, or ⌊ticks/90⌋ ≠duration_ms), the cue iscue_section_mismatch. Where no section states slots, a cued break takes its room policy'sslots. A scheduled break is unslotted.Refusals, never silent drops. A cued break in the period that lies outside every window is refused
outside_window, as revenue-share refuses such an impression. When two rooms' breaks overlap, the report refusesbreak_overlaprather than count one break twice. Breaks outside the period belong to another period's report.The fill is impressions per slot. That number is audience × share of slots filled, and no record states an audience. So
aboveandbeloware relative to the period's own rate. A reported statement that is low on every line is flagged only against the signed statement (§10.3, §15).Signed figures on the period line only. Statement lines are per split, and a party's part is rounded once per line.
Changes to #539's files are visibility only:
revenue_share::{the_runs, asset_at}becomepub(crate), and eight CLI helpers indx/share.rsbecomepub(super).Checks
Builds, tests and Python verifiers ran on the Framework box via
[email protected] ~/kani-logs/remote/rb. Light scripts ran locally. Head is026e5416, after merging #539's latest commit.cargo test --locked --no-default-features --features opportunity_report --lib opportunity_report::cargo test --locked --no-default-features --features opportunity_report --test opportunity_report… --test revenue_sharecargo test --features "$WAI_FEATURES" --test opportunity_report --test revenue_shareand--lib opportunity_report::cargo run --features opportunity_report --bin wai_opportunity_vectors verify ../live-conformance/opportunitypython3 -I live-conformance/opportunity_report_verify.py live-conformance/opportunityrevenue_share_verify.py,browser_sink_verify.py,sink_energy_verify.py,live_ads_verify.py,receipt_ledger_verify.pycargo test --features quickstart --bin wai --test cli_ops;… quickstart,opportunity_report …;… quickstart,revenue_share --test cli_opscargo test --lib catalogue(6),--lib registry(20),--test cli_registry(6),--lib vocab_pin_terms(1)wai ops export --check ../catalogue/ops.json;wai registry export --check;node wai/wai-studio/scripts/actions.mjs --checkcargo clippy --all-targetswithquickstart,opportunity_report,quickstart,revenue_share,quickstartwai breaking --against 564a42df(merge base with main)cargo metadata --locked --offline --format-version 1python3 ~/kani-logs/wfsteps.py HEAD HEAD^1 HEAD^2;ruby -ryamlover.github/workflows/*.ymlcheck-tests-in-ci.py,check-workflow-concurrency.sh,check-spec-refs.py,check-wai-section-refs.py,check-no-vanity-metrics.sh,test-public-text-checks.sh,check-comparative-prose.sh,check-orphan-sources.py,check-wai-ops-doors(-selftest)check-public-names.shover the 28 changed files;grep -Eof commit messages and this bodyFalsifications
All were run after committing. Each mutation was applied in the rb snapshot with an anchor check and restored with
git checkout.--lib opportunity_report::sectionwai_opportunity_vectors verifybelowinvertedsection_13…test 101; Python verifier 1 (this second guard was added after the first run let it pass)statement.check's--dry-runsample removedcli_opsagrees()made always trueNot in this PR
WIJ1records, which cue-injection §8 does;No existing record's signed format changes.
🤖 Generated with Claude Code