# WAI Extension: Revenue Share > Status: Draft. Registers the record `wai.delivery.revenue_share`: what each content owner of a > linear channel is owed from the ads sold in the channel's breaks, as a statement anyone holding > the public records recomputes. An operator and every owner it names sign a **share contract**, > `WRC1`: its period, its channel and the key that signs the channel's program-as-run, the > carriers whose ad evidence belongs to the channel, the map from each asset to a **split** of > integer millionths among owners and the operator, and the rule for a break that falls between > programmes. The operator signs a **statement**, `WRS1`, for one party and one period: the > invoices of [receipt-ledger](receipt-ledger.md) it rests on, the program-as-run windows of > `wai.video.channel` it places impressions in, and one line per split and class, each with the > impressions attributed, the revenue the invoices' tariffs priced them at, the party's share of > it divided by the largest-remainder rule, and the records the line came from. A verifier given > the contract, the windows and the ledgers' own verification documents recomputes every line and > refuses a statement that does not recompute. No new transport, no payment and no currency > conversion: a statement is the recomputable figures a payment to an owner rests on. The > reference implementation is the `revenue_share` module of `wai-rs` (feature `revenue_share`); > the corpus is [`live-conformance/share/`](../live-conformance/share/), and its second > implementation is `live-conformance/revenue_share_verify.py`. > Keywords **MUST**, **MUST NOT**, **SHOULD**, **MAY** are RFC 2119/8174. > > Texts read for this revision: the WAI texts this one cites; ISO 4217 (the alphabetic currency > code); RFC 3339 §5.6, for the date-time form of §5.4; RFC 8032; RFC 8259; FIPS 180-4. > > Why the name: the extension states how revenue is shared, and the record names both of its > parts, the contract and the statement, under one string, as `wai.delivery.ledger` names its > tariff and its invoice. ## 1. Scope In scope: the share contract, its splits, its signatures and when two contracts overlap (§3); the program-as-run as a verifier is given it, the JSON carriage of a `wai.video.channel` receipt, whose signed bytes this text writes out and does not change (§4); the evidence, invoices of the receipt ledger and the impressions their sources state, with their instants (§5); attribution, from an impression's instant to an asset and its split (§6); the statement, its lines, rounding and citations (§7); verification (§8); how a statement composes with the ledger (§9); and the operations (§10). Out of scope: a transport; paying an owner, an owner's account and any contact with a party outside the records; invoicing a buyer, which the receipt ledger does; converting a currency; how an operator chooses an owner's share; placing in time a presentation whose marker states no time this text reads (§5.4), which is kept in a class of its own; and the records themselves, which their own extensions define, verify and leave as they are. The channel receipt keeps its signed bytes: §4 writes them out for a verifier that is not `wai-rs`. Relationship to the core spec: `wai.delivery.revenue_share` is a **record** ([SPEC](../SPEC.md) §5): a signed record a WAI tool emits and verifies. It names no payload format and is not dispatchable. ## 2. Terms - **Operator**, **owner**: Ed25519 keys (RFC 8032). The operator carries the channel, sells its breaks and signs contracts and statements; an owner holds programmes the channel airs. A **party** of a contract is its operator or one of its owners. - **Time**: microseconds since 1970-01-01T00:00:00Z, the unit of receipt-ledger §2. A **period** is a span of time from its `start` (included) to its `end` (excluded). A channel receipt states milliseconds since the same instant; an instant of *m* milliseconds is *m* × 1000 microseconds, computed without overflow. - **Run**: one `wai.video.channel` receipt, a signed program-as-run window (§4). Its **window** is `[window_start_ms, window_end_ms)`, and an **entry** is one slot of its schedule. - **Programme**: an entry of kind `program`. An entry of kind `ad` or `filler` is not a programme. - **Carrier**: what delivers the channel's ads: a room of [live-ads](live-ads.md), named by its room id, whose break-form receipts the ledger bills; or a stitcher of [stitched-presentation](stitched-presentation.md), named by the key that signs its pod-input records. - **Ledger document**: a verification document of receipt-ledger §7.1, for one invoice. - **Impression**: one ad presented or billed, as the ledger counts it (§5.2). - **Minor unit**, **amount**: as receipt-ledger §2: an amount is an integer of millionths of a currency's minor unit. - **ppm**: an integer share in millionths, of 10^6. - *u64*, *u32*, *u16*, *u8*: little-endian unsigned integers of that many bits in the records of §3 and §7; the channel receipt's signed bytes (§4.2) are big-endian, as `wai.video.channel` writes them. A **digest** is SHA-256 (FIPS 180-4), 32 bytes; **zero** of a key or digest field is 32 zero bytes. A *text* field is a u16 length and that many bytes of UTF-8. ## 3. The share contract ### 3.1 Layout | field | size | meaning | |---|---|---| | `magic` | 4 | `WRC1` (ASCII) | | `version` | 1 | 1 in this revision | | `operator` | 32 | the operator's key, which signs the contract and every statement under it | | `start`, `end` | 8 each | u64: the period the contract is in force | | `currency` | 3 | three capitals `A`–`Z` (ISO 4217): the currency of every invoice it shares | | `channel` | 2 + *n* | a text field of 1 to 1024 bytes: the `channel_id` of the channel's runs | | `channel_signer` | 32 | the key that signs the channel's runs | | `rule` | 1 | for an impression in an entry that is not a programme (§6.2): 1 **preceding**, 2 **following**, 3 **between** | | `between` | 2 | u16: the index of the **between split** (§6.2, §6.3) | | `carriers` | 2 + 33 × *c* | a u16 count, then each carrier: `kind` (u8: 1 a room, 2 a stitcher) and `id` (32: the room id, or the stitcher's key), in strictly ascending order of (`kind`, `id`) | | `owners` | 1 + 32 × *o* | a u8 count, then each owner's key, in strictly ascending order | | `splits` | 2 + … | a u16 count, then each split (§3.2) | | `assets` | 4 + … | a u32 count, then each asset: `asset` (a text field of 1 to 1024 bytes, an `asset_id` of the channel's schedule) and `split` (u16, the index of its split), in strictly ascending order of `asset`'s bytes | | `operator_sig` | 64 | §3.3 | | `countersigs` | 64 × *o* | each owner's countersignature, in the order of `owners` (§3.3) | ### 3.2 Splits A split divides revenue among parties: | field | size | meaning | |---|---|---| | `operator_ppm` | 4 | u32: the operator's share, 0 to 10^6 | | `m` | 1 | u8: the owners it names | | `shares` | 5 × *m* | each: `owner` (u8, the owner's index in `owners`) and `ppm` (u32, its share), in strictly ascending order of `owner` | The **parties** of a split, in their **order**, are its owners in the order it lists them, then the operator when `operator_ppm` is above 0. A party **holds a share** of a split when it is one of its parties. The shares of a split sum to 10^6 exactly: a split is the whole of the revenue it is given, and no part of it is left unassigned. ### 3.3 Digest and signatures The **body** of a contract is its bytes before `operator_sig`, and its **digest** is SHA-256 over the body. `operator_sig` is Ed25519 by `operator` over the bytes `wai:share-contract` (ASCII) and 0x01, followed by the body. Each owner's countersignature is Ed25519 by that owner over the bytes `wai:share-accept` (ASCII) and 0x01, followed by the body; 64 zero bytes in its place state that the owner has not countersigned. An operator offers a contract with every countersignature zero, and each owner fills its own. Every signature is verified strictly, as [SPEC](../SPEC.md) §7 *Signatures* requires: a key that fails step 1 or 2 is `bad_key`, and a signature that fails a later step is `bad_signature`. A contract is **in force** only when every owner it names has countersigned it: the splits and the asset map bind each owner only by its own signature, and a contract some owner did not sign shares nothing. ### 3.4 Reading and rules A reader reads exactly the bytes it is given as one contract, in the order of §3.1, and refuses at the first of these that holds: fewer than 4 bytes, `truncated`; a magic other than `WRC1`, `malformed`; no fifth byte, `truncated`; a version other than 1, `unknown_version`; the bytes end before a field the layout requires, `truncated`; bytes after the last countersignature, `malformed`. It then refuses as `contract_invalid` a contract that breaks any of these: - `start` is below `end`; `currency` is three capitals `A`–`Z`; - `operator` and `channel_signer` are not zero, and `operator` is not an owner; - `channel` and every `asset` are UTF-8 of 1 to 1024 bytes; - `rule` is 1, 2 or 3, and `between` is the index of a split; - `carriers` has at least one entry, each `kind` 1 or 2 and each `id` not zero, in strictly ascending order; - `owners` has at least one key, none zero, in strictly ascending order; - `splits` has at least one split; in each, the owners are in strictly ascending order of index, each index below the count of `owners`, and each `ppm` above 0; and every owner holds a share of at least one split; - `assets` has at least one entry, in strictly ascending order, each `split` the index of a split. It refuses as `split_not_whole` a contract with a split whose `operator_ppm` and `ppm`s do not sum to 10^6. Then it verifies `operator_sig` (`bad_key`, `bad_signature`), then each countersignature in turn: one of 64 zero bytes is `not_countersigned`, and one that does not verify is `bad_key` or `bad_signature`. A refusal of a signature names the operator, or the owner and its index. ### 3.5 Contracts that overlap Two contracts **overlap** when their periods share an instant and they name the same `channel`, or a carrier in common. An asset aired under two contracts at once would have two owners, and a statement under either would share revenue the other also shares; a verifier holding both refuses a statement under either (§8.2 step 2, `contract_overlap`). An operator **MUST NOT** sign two contracts that overlap; one that changes a contract's terms signs a new contract whose period begins where the old one's ends. ## 4. The program-as-run ### 4.1 Its JSON carriage A run is carried as one JSON object (RFC 8259) with exactly these members; a byte field is lowercase hexadecimal of its exact length, and an integer a JSON integer from 0 to 2^64 − 1: | member | value | |---|---| | `channel_id` | a string: the channel | | `schedule_root` | 32 bytes: §4.2 | | `schedule` | an array of entries, each `{"asset_id", "start_ms", "duration_ms", "kind"}`: `asset_id` a string, `kind` one of `program`, `ad` and `filler` | | `window_start_ms`, `window_end_ms` | the window | | `aired` | an array of integers: the indices of the entries on air in the window | | `work_schedule_ops` | the entries' count, as the receipt states it | | `joules_micro` | the assembly's energy, or 0 unmetered | | `energy_provenance` | its class's label (energy-measurement §2.7: `ModelBased`, `Estimator`, `OnChipCounter`, `CalibratedInstrument`), or `null` unmetered | | `energy_uncertainty`, `energy_counter_filtering`, `energy_calibration_ref` | only for a class that carries them, as live-ads §8.2 writes them | | `grant` | `{"grant_hash", "capability", "joule_ceiling_micro", "funds_ceiling"}`, `funds_ceiling` `null` for none | | `parent_receipt_hash` | 32 bytes: the run before it in the channel's chain, or `null` | | `signer_pubkey` | 32 bytes: the channel signer's key | | `signer_id` | a string | | `sig` | 64 bytes: §4.2 | A run **reads** when it is such an object and each entry's `start_ms` + `duration_ms` is at most 2^64 − 1. The legacy class label `HwShunt` (energy-measurement §2.6) does not read in this carriage. ### 4.2 Its signed bytes and identity These are the bytes `wai.video.channel` signs, written out; BLAKE3 throughout, integers big-endian: - an entry's **leaf**: BLAKE3 over `wai:video-channel-entry` (ASCII) and 0x01, `asset_id`'s length (u32) and bytes, `start_ms` (u64), `duration_ms` (u64) and its kind's tag (u8: 1 `program`, 2 `ad`, 3 `filler`); - the **schedule root**: the Merkle root over the leaves in schedule order, [jwp-receipts](jwp-receipts.md) §2.2's tree, each leaf taken as a content hash (its first leaf form) and the final one duplicated on an odd level; all zero for an empty schedule; - the **signing payload**: `wai:video-channel-receipt` (ASCII) and 0x01; `channel_id`'s length (u32) and bytes; `schedule_root`; `window_start_ms`, `window_end_ms`, `work_schedule_ops` and `joules_micro` (u64 each); the class in its signed encoding (energy-measurement §2.7), the tag byte 0 for none; the grant reference as live-ads §8.4 writes it (`grant_hash`, `capability`'s length (u32) and bytes, `joule_ceiling_micro` (u64), then 1 and `funds_ceiling` (u64), or 0); 1 and `parent_receipt_hash`, or 0; the count of `aired` (u64) and each index (u64); the count of `schedule` (u64) and each entry's leaf; and `signer_pubkey`, then `signer_id`'s length (u32) and bytes; - `sig`: Ed25519 by `signer_pubkey` over the signing payload, verified strictly; - the run's **identity**, its receipt hash: BLAKE3 over `wai:video-channel-receipt-id` (ASCII) and 0x01, the signing payload and `sig`. ### 4.3 When a run verifies A run verifies when: 1. `schedule_root` is the schedule root of its entries, and `work_schedule_ops` their count; 2. `window_start_ms` is below `window_end_ms`; 3. the schedule is continuous: each entry starts where the one before it ends; 4. `aired` is exactly the indices, ascending, of the entries that touch the window: those whose `start_ms` is below `window_end_ms` and whose `start_ms` + `duration_ms` is above `window_start_ms`; 5. the figure and its class cohere as live-ads §8.5 rule 5 states it; and 6. its signature verifies. So the program-as-run is the schedule the channel signer signed, and what aired in a window is recomputed from it rather than read from a log. ## 5. The evidence ### 5.1 Invoices A statement rests on **invoices** of the receipt ledger, each given as its ledger document (receipt-ledger §7.1): the tariff, the invoice, the invoice before it in its chain, and the sources. A ledger document is **accepted** when the receipt ledger's verification (§7.2 there) accepts it. Its tariff states the prices, its invoice the period and the records, and its sources the impressions. A statement prices nothing itself: an impression's revenue is the price the invoice billed it at. Each invoice of a statement is one the operator sold as the seller of its tariff, in the contract's currency; the buyer is whoever bought the channel's breaks under that tariff. A channel whose breaks several buyers bought rests on several invoices, one chain per tariff. ### 5.2 Impressions and their classes An accepted ledger document contributes, from its sources in order: - for an `ads` source whose `room` is a carrier of kind 1: each receipt in the source's order, and each of its impressions in slot order that the ledger counts (receipt-ledger §6.3 and §8.1): - under a policy that requires presentation claims, an impression that counts, its own claim `presented` (ad-presentation §9.2): class **presented**, its records the receipt (kind 6) and its own claim (kind 7); - under a policy that does not, a billable impression (quartile at least 1): class **beacons**, its record the receipt (kind 6); - for a `stitched` source: each record the source accepts whose `signer` is a carrier of kind 2, each of its ads in slot order, and each presentation of the ad (stitched-presentation §7.4, a presented own claim) in the order its claims are given: class **presented** when its instant is stated (§5.4) and **unplaced** otherwise, its records the pod-input record (kind 8) and the claim (kind 9). Record kinds are receipt-ledger §5.2's. Every other source, and every impression of a carrier the contract does not name, contributes nothing: an invoice may bill a buyer for several channels, and a statement shares the impressions of its own. An impression's **price** is its invoice's tariff's `ads` price (receipt-ledger §4.1): per presented impression for the classes presented and unplaced, the unit `presented_impressions` bills; per billable impression for the class beacons, the unit `billable_impressions` bills. So an impression is priced at the unit the invoice billed it under, and the classes keep apart what the players' own claims show presented and what rests on a decider's beacons alone. A class is never summed into another: each has its own lines (§7.2). ### 5.3 Its instant An impression's **instant** places it on the channel's timeline: - an impression of an `ads` source: its room's `t0` plus the `t` of the break its receipt names (live-ads §4.1, placed as receipt-ledger §5.3 places it). Every impression of a break shares the break's instant: a break is attributed whole; - a presentation of a stitched record: the instant its marker states (§5.4). A presentation whose marker states none has no instant: it is **unplaced**. ### 5.4 The instant a marker states A marker of carriage 1 or 2 (stitched-presentation §3.1) carries the `START-DATE` of its date range, the second long field of its body. It **states** an instant when it is exactly this form, in ASCII, of RFC 3339 §5.6's `date-time` with its letters in capitals: ``` YYYY "-" MM "-" DD "T" hh ":" mm ":" ss [ "." 1 to 9 digits ] ( "Z" / ( "+" / "-" ) hh ":" mm ) ``` with `YYYY` a year of four digits, `MM` 01 to 12, `DD` 01 to the days of that month in the Gregorian calendar, `hh` 00 to 23, `mm` 00 to 59 and `ss` 00 to 59 (an offset's `hh` and `mm` the same), and the instant it names, in microseconds, at or after 1970-01-01T00:00:00Z. The instant is the date and time less the offset, its fraction truncated to the microsecond. A marker of carriage 3 carries no date (§3.4 there): its presentations are unplaced, as are those of a `START-DATE` that does not state an instant. ## 6. Attribution ### 6.1 The run of an instant The runs a verifier is given are of the contract's channel and signer and do not overlap (§8.2 step 4). The **run** of an instant is the run whose window holds it; the **entry** of the instant is the entry of that run's schedule whose span holds it. An impression with an instant and no run, or a run and no entry (an instant past its schedule's end), aired in no window the verifier holds: it is refused `outside_window`. ### 6.2 The asset and its split The entry of an impression's instant gives its **asset**: - a programme gives its own `asset_id`: a break inside a programme is that programme's; - an entry that is not a programme gives, by the contract's `rule`: for **preceding**, the `asset_id` of the last programme before it in the run's schedule; for **following**, that of the first programme after it; when there is no such programme, or for **between**, no asset. An impression with an asset is attributed to the asset's split in the contract's `assets`; an asset the contract does not map is refused `asset_unmapped`. One with no asset is attributed to the between split. The rule applies to the run's own signed schedule, so anyone holding the run finds the same programme. ### 6.3 Unplaced impressions An unplaced impression is attributed to the between split, in the class unplaced. It is revenue the channel earned in some break that no record places in a programme, and the contract's between split is how its parties agreed to share such revenue. It is never counted in the class presented: a statement states it apart, and an owner sees how much of its revenue no record placed. ## 7. The statement ### 7.1 Layout | field | size | meaning | |---|---|---| | `magic` | 4 | `WRS1` (ASCII) | | `version` | 1 | 1 in this revision | | `contract` | 32 | the contract's digest (§3.3) | | `party` | 32 | the party it is for: the operator or an owner | | `start`, `end` | 8 each | u64: the period it states | | `currency` | 3 | the contract's | | `invoices` | 2 + 32 × *i* | a u16 count, then each invoice's digest (receipt-ledger §6.7), in strictly ascending order | | `runs` | 2 + 32 × *r* | a u16 count, then each run's identity (§4.2), in strictly ascending order | | `lines` | 2 + 67 × *l* | a u16 count, then each line (§7.2), in strictly ascending order of (`split`, `class`) | | `total` | 8 | u64: the sum of the lines' amounts | | `sig` | 64 | §7.5 | ### 7.2 Lines A line is 67 bytes: | field | size | meaning | |---|---|---| | `split` | 2 | u16: the split's index | | `class` | 1 | 1 presented, 2 beacons, 3 unplaced (§5.2) | | `impressions` | 8 | u64: the impressions of the class attributed to the split | | `revenue` | 8 | u64: the sum of their prices | | `ppm` | 4 | u32: the party's share of the split | | `amount` | 8 | u64: the party's part of the revenue (§7.3) | | `cited` | 4 | u32: the records the line cites (§7.4) | | `cites` | 32 | their citation digest (§7.4) | There is one line for each split of which the party holds a share and each class with at least one impression attributed to that split, and none other. A party's statement so states the whole revenue of every split it shares in, and its part of each. ### 7.3 Revenue, shares and rounding A line's revenue is divided among the parties of its split by the **largest-remainder rule**, so that the parts are integers and sum to the revenue exactly: 1. For each party *i* of the split, in its order (§3.2), its **quota** is `revenue` × `ppm`*ᵢ*, computed in integers wide enough not to overflow; its **base** is ⌊quota / 10^6⌋, and its **remainder** is quota − base × 10^6. 2. The **leftover** is `revenue` less the sum of the bases. It is less than the count of parties. 3. The parties with the largest remainders, as many as the leftover, each receive one more than their base; between equal remainders, the earlier party in the order receives it first. 4. A party's **part** is its base, plus one when step 3 gives it one. The parts of a split's parties sum to its revenue, whoever's statement states them: the operator's statement and each owner's state the same revenue for a split and class, and their parts sum to it. Rounding is applied once per split and class over the statement's period, never per impression, so it does not accumulate. ### 7.4 Citations Each line cites the records it came from: for each impression attributed to its split in its class, the impression's records (§5.2), the run that placed it (kind 10, its identity) when it has an instant, and the invoice that billed it (kind 11, its digest). `cited` is their number, each record counted once, and `cites` is SHA-256 over the bytes `wai:share-cites` (ASCII) and 0x01, followed by each cited record's `kind` (u8) and identity (32), in ascending order of (`kind`, identity). A line that cites no record has no source (`line_unsourced`, §8.2 step 7). An owner shows one line to an auditor with the records it cites, the contract and the runs. Kinds 10 and 11, like every kind a citation digest names, are registered in [receipt-ledger](receipt-ledger.md) §5.2. ### 7.5 Digest and signature The **digest** of a statement is SHA-256 over its bytes before `sig`. Its signature is Ed25519 by the contract's `operator` over the bytes `wai:share-statement` (ASCII) and 0x01, followed by the bytes the digest covers, verified strictly (SPEC §7 *Signatures*). ### 7.6 Reading and rules A reader reads exactly the bytes it is given as one statement, as §3.4 reads a contract with `WRS1` for `WRC1` (`truncated`, `malformed`, `unknown_version`), and refuses as `share_statement_invalid` one that breaks any of these: - `start` is below `end`; `currency` is three capitals `A`–`Z`; `party` is not zero; - `invoices`, `runs` and `lines` are each in the strictly ascending order §7.1 gives it; - each line's `class` is 1, 2 or 3, its `impressions` and `cited` above 0, its `ppm` 1 to 10^6, and its `amount` at most its `revenue`. Its signature is checked against the contract's operator (§8.2 step 3). ## 8. Verification ### 8.1 Inputs A verifier is given the **contract**; the **other contracts** it holds of the operator or of the channel, for the overlap check; the **statement**; the **runs**; and the **ledger documents**. Its verification document holds them as one JSON object with exactly the members `contract` and `statement` (hexadecimal), `contracts` (a list of hexadecimal strings), `runs` (a list of runs in their carriage, §4.1) and `ledgers` (a list of ledger documents, receipt-ledger §7.1). A document that is not such an object is refused `malformed`. ### 8.2 Steps It runs these steps and stops at the first refusal, which it reports with the reason and where: 1. **The contract** (§3.4), at `contract`; a signature's refusal at `contract` and `operator`, or `contract`, `owner` and the owner's index: `truncated`, `malformed`, `unknown_version`, `contract_invalid`, `split_not_whole`, `bad_key`, `bad_signature`, `not_countersigned`. 2. **The other contracts**, each at `contracts` and its index, a signature's place after it: each is read and verified as step 1, with those reasons; one whose digest is the contract's is the contract and is passed over; one that overlaps the contract (§3.5) is `contract_overlap`. 3. **The statement**, at `statement`: it reads (§7.6: `truncated`, `malformed`, `unknown_version`, `share_statement_invalid`); its `contract` is the contract's digest, its `party` the operator or an owner of the contract, and its `currency` the contract's: otherwise `contract_mismatch`; its period lies within the contract's: otherwise `outside_contract`; its signature verifies under the operator (§7.5): `bad_key`, `bad_signature`. 4. **The runs**, each at `run` and its index: it reads (§4.1: `malformed`); it verifies (§4.3: `run_invalid`); its `channel_id` is the contract's `channel` and its `signer_pubkey` the `channel_signer`: otherwise `run_foreign`; its window shares an instant with the window of a run before it: `run_overlap`. 5. **The ledger documents**, each at `ledger` and its index: it is verified as receipt-ledger §7.2 verifies one, a refusal being that extension's reason with its place after the index; its invoice's `seller` is the operator and its `currency` the contract's: otherwise `invoice_foreign`; its period lies within the statement's: otherwise `outside_period`; and no record of kinds 6 to 9 in its invoice's `records` is in the `records` of an invoice before it, and no ad receipt of its sources names the room, the cue and the session an ad receipt of a document before it names: otherwise `impression_duplicate`. A ledger refuses a record billed twice within one invoice and one chain (receipt-ledger §5.2, §6.9); this step refuses one billed by two invoices of a statement, under two tariffs among them. 6. **The impressions** (§5.2), in the order the documents give them, each at `ledger`, its index, `source` and the source's index: an impression with an instant (§5.3) whose instant does not lie within the statement's period is `outside_period`; one that aired in no window (§6.1) is `outside_window`; one whose asset the contract does not map (§6.2) is `asset_unmapped`. 7. **The figures**, at `statement`, recomputed from the impressions as §7.2 to §7.4 compute them for the statement's party, and compared in this order: 1. a line whose split and class give the party no impression, or that states more impressions than they give: `line_unsourced`, a line no signed record covers; 2. a line whose `cited` or `cites` is not the records it came from: `citation_mismatch`; 3. any other difference (the invoices, the runs, a line missing, fewer impressions, a revenue, a `ppm`, an amount, the `total`): `share_statement_mismatch`. A figure that cannot be held in its field is a difference. ### 8.3 Outcome - **refuse**: the reason and where. - **accept**: the statement's digest; the contract's digest; the party and whether it is the operator or an owner; the currency and the period; the invoices and the runs; each impression of the contract's carriers, in the order of step 6, with the ledger document and source it came from, its records, its class and price, its instant, run, entry and asset (each `null` when it has none) and its split; each line with its split, class name, impressions, revenue, the party's `ppm` and amount, its cited records, and the **division**, every party of its split with its `ppm` and part; and the total. The division is not signed: anyone holding the records computes it, and it shows that the parts of a split sum to its revenue. ## 9. The statement and the receipt ledger A statement composes with the ledger and duplicates none of it: - **Its sources are the ledger's.** The impressions a statement shares are those of the `ads` and `stitched` sources of invoices the ledger accepted, verified as the ledger verifies them: by live-ads with ad-presentation, and by stitched-presentation. A statement recomputes no decision, no claim and no presentation; it reads the ledger's counts and verdicts. - **Its prices are the tariff's.** An impression's revenue is its invoice's price for the unit that billed it, so an owner's revenue is a part of what the buyer was invoiced, never a figure the operator states. - **Its records are the invoice's.** Each impression is named by the records the invoice holds, and the statement cites the invoice itself. A statement adds the two things the ledger does not hold: the instant of each impression on the channel's program-as-run, and the split the contract gives the programme that aired at that instant. - **An operator that bills a channel's breaks** puts the sources of the channel's carriers into the ledger as the ledger receives any source (receipt-ledger §5.1, §9), under a tariff whose scope names the carriers' deciders and stitchers (receipt-ledger §4.4). The verification document the ledger keeps with each invoice (receipt-ledger §9: `GET /v1/invoices/{digest}`) is the ledger document a statement is given, unchanged. Paying an owner its part, and an owner invoicing the operator for it, are not sources the ledger defines, and this revision defines none. ## 10. Operations `wai` runs the operations of this extension, under the agent rules of the operation catalogue (the `--json` envelope, the exit codes, `--dry-run` on every operation that writes, `--yes` before a file is replaced). A refusal by this text has its reason as the operation's code. | operation | command line | does | |---|---|---| | `contract.create` | `wai contract create --key [--out F]` | the operator's contract from its terms, signed by the operator with every countersignature zero (§3.3) | | `contract.update` | `wai contract accept --key [--out F]` | an owner's countersignature added, after the contract's rules and the operator's signature are checked | | `statement.create` | `wai statement create --party --start µs --end µs --key [--out F]` | the statement of a party and a period, computed from a verification document without its statement (§8.1), signed by the operator, written with its document | | `statement.verify` | `wai statement verify ` | a verification document's outcome (§8.3); exit 1 with the reason on a refusal | ## 11. Reasons The codes this extension adds, each with where it is raised: | reason | raised at | |---|---| | `contract_invalid` | §3.4, §8.2 steps 1 and 2 | | `split_not_whole` | §3.2, §3.4, §8.2 steps 1 and 2 | | `not_countersigned` | §3.3, §8.2 steps 1 and 2 | | `contract_overlap` | §3.5, §8.2 step 2 | | `share_statement_invalid` | §7.6, §8.2 step 3 | | `contract_mismatch` | §8.2 step 3 | | `outside_contract` | §8.2 step 3 | | `run_invalid` | §4.3, §8.2 step 4 | | `run_foreign` | §8.2 step 4 | | `run_overlap` | §6.1, §8.2 step 4 | | `invoice_foreign` | §5.1, §8.2 step 5 | | `impression_duplicate` | §8.2 step 5 | | `outside_window` | §6.1, §8.2 step 6 | | `asset_unmapped` | §6.2, §8.2 step 6 | | `share_statement_mismatch` | §8.2 step 7 | A verifier of this extension also raises, with the meaning this text gives them: `truncated`, `malformed` and `unknown_version` for a contract or a statement that does not read, and `malformed` for a document or a run that does not read; `bad_key` and `bad_signature` for their signatures; `outside_period` (receipt-ledger §10) for an invoice or an impression outside the statement's period; `line_unsourced` (fleet §10) for a line no impression gives; `citation_mismatch` (receipt-ledger §10) for a line's citations; and, at a ledger document, every code the receipt ledger raises (receipt-ledger §10 and the codes it lists). ## 12. Conformance [`live-conformance/share/`](../live-conformance/share/) holds the corpus, in one file, `vectors.json`, written by `wai_revenue_share_vectors gen` from fixed seeds and from the sources of the ledger corpus (`live-conformance/ledger/`): a room's break-form receipts under a policy that requires claims and under one that does not, and three streams stitched by others, one of whose markers are DASH events. The ledger documents, the runs and the contracts are held once, by name, and each vector is a verification document (§8.1) naming them, with the outcome §8.3 gives it: - **Accepted**: a channel's month, its two windows airing two owners' programmes with mid-roll breaks and an ad slot between programmes, its impressions from two invoices of one chain, one of the room's breaks and one of the stitched streams; the statement of each owner and of the operator under the rule preceding, so that the three statements' parts of each split sum to its revenue; and an owner's statement under the rules following and between. - **Refused**: each reason of §11 at least once, each vector a control of one defect; each code §11 reuses; and a ledger document refused by the receipt ledger, at its place. `wai_revenue_share_vectors verify` and the test `tests/revenue_share.rs` check that the file regenerates byte for byte, that `wai-rs` gives every vector its outcome, that every reason of §11 refuses a vector, and that §11 lists exactly the reference's codes; the test also holds the worked example, three statements of one month computed and then recomputed from the public records alone, and the module's unit tests the rounding rule's ties. `live-conformance/revenue_share_verify.py` is the second implementation, written from this text: it shares no code with `wai-rs`, verifies signatures with WAI's strict rule written from RFC 8032 (`claim-conformance/_ed25519.py`) and BLAKE3 with `claim-conformance/_blake3.py`, verifies each ledger document with that corpus's own second implementation (`receipt_ledger_verify.py`), reads every contract, run, marker and statement itself, recomputes every attribution, line, division and citation, gives every vector the same outcome, requires every mutated copy of the corpus to fail, and drops each of its own checks in turn and requires the corpus to catch the weakened verifier. ## 13. Security and privacy considerations - **Who signs what.** Each owner signs the splits and the asset map it is bound by; the channel signer signs what aired; the decider, the stitcher and each player sign the impressions; the buyer signs the prices; the operator signs the statement. An operator cannot move an impression to another programme, price it at another price or round a part against an owner: the verifier recomputes every line from records the operator did not sign alone. - **What the operator still controls.** The records show what was invoiced from the contract's carriers. An operator that sells a break without invoicing it, or carries the channel through a room or a stitcher the contract does not name, keeps that revenue out of every statement; the contract's carriers are what the owners agreed to, and an owner that suspects more carriers asks for them by name. - **The between split.** Revenue in an entry that is not a programme, and every unplaced presentation, goes to the between split. An owner that agrees a between split in which it holds no share agrees to receive nothing from such breaks, and a statement states their revenue apart so that the owner sees it. - **Double counting.** One invoice and one chain bill a record once (the ledger's rules); two invoices of one statement may not bill one impression (`impression_duplicate`); two contracts may not share one channel or carrier at once (`contract_overlap`); and two runs may not place one instant (`run_overlap`). A verifier holding fewer contracts than the operator signed cannot see an overlap with the ones it lacks. - **What a statement reveals.** A statement names the invoices and runs it rests on, and a line states its split's whole revenue: the co-owners of a split, and the operator, see the same figures. A verification document holds the ledgers' sources, whose receipts name sessions and whose claims name session keys made for one session alone (ad-presentation §3, stitched-presentation §5.2). It travels between the operator, the owner and an auditor they choose.