open-standards/wai/extensions/receipt-ledger.md
Transaction Science 6e03ec7fa5
All checks were successful
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 38s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 34s
wai-app and Create / wai-app · does this change touch it (push) Successful in 33s
wai-audit collector and player integration / does this change touch it (push) Successful in 21s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 30s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 2m3s
wai-quantum for JavaScript / does this change touch it (push) Successful in 33s
wai-quantum studio and desktop / does this change touch it (push) Successful in 37s
WAI operation catalogue / does this change touch it (push) Successful in 1m31s
wai-fleet service / does this change touch it (push) Successful in 1m23s
wai-ledger service / does this change touch it (push) Successful in 1m6s
wai-sink-android native sink library / does this change touch it (push) Successful in 49s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Successful in 1m18s
wai-sink-swift native sink package / does this change touch it (push) Successful in 49s
WAI Studio / does this change touch it (push) Successful in 1m16s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 2m13s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 3m11s
wai-audit collector and player integration / collector · linux (push) Successful in 2m43s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 2m33s
wai-ledger service / service · linux (push) Successful in 2m56s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m54s
wai-quantum for JavaScript / javascript · linux (push) Successful in 3m55s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 1m8s
wai-quantum studio and desktop / studio · browser (push) Successful in 4m57s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 6m58s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 5m6s
wai-fleet service / service · linux (push) Successful in 3m28s
wai-ledger service / service · macos (push) Successful in 1m7s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 3m44s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 7m38s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 9m55s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 8m36s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 5m22s
wai-fleet service / service · macos (push) Successful in 35s
WAI Studio / Studio in WebKit · linux (push) Successful in 12m20s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Successful in 17m53s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 19m20s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 18m38s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 11m20s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m2s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 14m27s
Tariff version 8 bills storage held over time by byte-days, each record's byte-seconds recomputed from the holder's signed snapshots
WAI's receipt ledger had no source for storage that is not a package:
a stream's DVR window, whose objects change with every segment admitted
and evicted, and a clip cut from it and kept. waiTransport meters both
(wai-additions §38) and cannot bill them. Version 8 is that source.

- A snapshot, WLS1: what one stored set lists at one instant, signed by
  its holder when the listing changes: its objects, their bytes, and the
  digest of its listing (each object by SHA-256 and length).
- A storage record, WLH1: the bytes the set held over an interval, in
  byte-seconds, naming its snapshots by digest.
- The rule: the snapshots cover the interval (the first at its start,
  each after the one before, none at or past its end), and the record's
  byte-seconds are floor(sum bytes x (next instant - instant) / 10^6).
  Any other figure is storage_mismatch; snapshots that do not cover it,
  outside_interval; snapshots not the record's, snapshot_mismatch; a
  record or snapshot breaking its rules, storage_invalid.
- A tariff of version 8 adds `storage` (per 10^9 byte-days) and a holder
  in its scope (kind 9). One line per holder in byte_days, rounded down
  once per line, citing records (kind 26) and snapshots (kind 27), each
  billed once in a chain. A record lies in the period that holds its
  interval: overlapping records of one set on one invoice are
  record_overlap, and one reaching into a billed period outside_period.
  Report §8.4 states each set's byte-seconds. Versions 1 to 7 unchanged.

Why snapshots: the ledger's evidence model bills a figure of a record its
party signed, recomputed by the verifier and placed in time by the time
the record states. Snapshots are signed as the listing changes and bind
bytes to objects by content hash; the record is a pure function of them.
A package's byte-days stay billed from the chain, since its bytes do not
change while it is kept.

Gates (Framework, [email protected], Rust 1.99.1):
- cargo test --release --no-default-features --features receipt_ledger,
  revenue_share,opportunity_report,impression_aggregate: lib
  receipt_ledger:: 23 of 23 (5 new), --test receipt_ledger 15 of 15 (2
  new: version 8's figures and refusals, a changed copy of a storage day
  refused), --test revenue_share 7 of 7, --test opportunity_report 6 of
  6, lib codecs::registry 15 of 15; wai-ledger 11 of 11 (one new: the two
  storage days issued byte for byte, a set's time held once).
- wai_receipt_ledger_vectors verify: regenerates byte for byte, every
  vector its outcome.
- receipt_ledger_verify.py (python3.14 -I): every vector agrees with
  wai-rs; 352 mutated copies fail; each of its 88 checks dropped is
  caught (12 new for version 8). Both read the same vectors.json.
- Planted faults, each alone, 10 plants of the 5 faults: caught by the
  Rust tests 10 of 10 and by the Python verifier 10 of 10.
- wai registry export --check, wai ops export --check: up to date.
- wai breaking --against b3f0aeb4e: no unacknowledged break (8
  acknowledged in the change note).
- clippy -D warnings on wai-ledger: clean; the new wai-rs code clippy
  clean.
- changelog-assemble --check, check-changelog-fragment, check-tests-in-
  ci, wai-conformance-lists check, check-workflow-concurrency.sh,
  check-comparative-prose.sh, check-public-names.sh
  --maintainer-products-only, check-wai-quantum-names, check-wai-
  section-refs, check-spec-refs, check-orphan-sources.py: pass.

Not built: waiTransport's side (it still meters and does not bill).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-10 10:42:44 -05:00

129 KiB
Raw Permalink Blame History

WAI Extension: Receipt Ledger

Status: Draft. Registers the record wai.delivery.ledger: invoice lines a customer can recompute from the signed records WAI already defines. A seller and a buyer both sign a tariff, WLT1: one currency, and one price for each unit those records state, the units of a room session (live-metering §4.4), the acknowledged bytes of each object class (settlement §3.3), the packages, entries and stored bytes of a package receipt (packaging §9), the counted impressions of a wai.video.ssai receipt of the break form (live-ads §8, ad-presentation §9.2) and the presentations of ads another party stitched (stitched-presentation §7.4); and the scope it covers, the rooms, the delivering parties, the packagers, and the ad deciders and stitchers whose records are billed under it. The ledger verifies each source by the extension that defines it, and the seller signs an invoice, WLI1, for a period: the records it was computed from, one line per source, unit and price, each line citing the records it came from, and the joules those records state, per scope and per acquisition class with their largest declared uncertainty, never summed across classes or scopes. Invoices under one tariff form a chain, and no record is billed in two of them. A verifier given the tariff, the invoice, the invoice before it and the sources recomputes every line and refuses an invoice that does not recompute. Beside the invoice, the ledger states two reports: the ad decisions reconciled against the players' presentation claims (for a stitched stream, stitched-presentation §7.5's own statement), and the delivery of each party under the one tariff with the bytes two parties were acknowledged for twice. A tariff of version 2 also prices media jobs (§4.5): a job is billed from its route record (route-record), its hops' OER/2 receipts and WAI's receipt of its output, in the units those receipts state. A tariff of version 3 prices a job by its capability and its operation (§4.6), since an encode and a decode spend different energy, and bills a job's work once, its route record and its hops' receipts, its output's receipt being the evidence a re-run may cite again (§6.9). A tariff of version 4 also bills what the rest of the work spends (§4.7): a room's bytes out, which a room-session receipt of version 2 states (live-metering §4.4), at a price per 10^9 bytes; a package's work once per run that made it, by the work units it states, its receipt the product each run cites; a package's storage by byte-days for each period it is held; and its invoices state every hop's energy, the hops not billed in a scope of their own (§6.6). A tariff of version 6 also prices a job per endpoint, and by the usage a third party's hop record states (route-record §6.2), and bills an upscale and a tone mapping by the subpixels their records state, each re-derived from what it read (§4.9). A tariff of version 7 also prices a transmission on a shared bearer (§4.10): the octets and pass time a publisher's schedule plans on a multicast or unidirectional instance it declared (carousel §5.4, bearer-receipts §4), at a price for each bearer class, unit and ceiling of the passes' rate, from a source that is a group with its declarations and its standing schedules or a node's own instance of one; an aggregated impression (§4.11), the count of an aggregate receipt (impression-aggregates), in a unit of its own; and an object an agent consumed (§4.12), from its consumption claims (ai-usage §6). A tariff of version 8 also prices storage held over time (§4.13), such as a stream's recent window or a clip cut from it, by byte-days, from a holder's storage record of a stored set over an interval, WLH1, whose byte-seconds the verifier recomputes from the holder's signed snapshots of what the set listed, WLS1, and refuses when they do not support it. Whatever the version, a job's output receipt is of an object its served hop states it delivered, where its route record states it (§5.1), and a route record's routing figures are never charges. No new transport, no payment and no tax: an invoice is the recomputable figures a payment rests on. The reference implementation is the receipt_ledger module of wai-rs (feature receipt_ledger) and the service wai/wai-ledger; the corpus is live-conformance/ledger/, and its second implementation is live-conformance/receipt_ledger_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 8032; RFC 8259; FIPS 180-4.

1. Scope

In scope: how one tariff prices rooms, packages, HTTP and relayed delivery, ads, and in version 7 transmissions on shared bearers, aggregated impressions and what agents consume together, and in version 8 storage held over time (§3); the tariff, its two signatures and its scope (§4); the snapshot and the storage record a holder signs (§4.13); the sources a ledger is given and what each contributes (§5); the invoice, its records, lines, citations and energy, its signature and its chain (§6); verification (§7); the two reports (§8); and the reference service (§9).

Out of scope: a transport; payment, a payment rail, tax and any contact with a party outside the records; how a seller chooses its prices; how a party measures its energy, which energy-measurement governs; and the records themselves, which their own extensions define, verify and leave as they are. The live-metering tariff and the settlement statement's tariff keep their meaning: this extension reads them, and changes neither.

Relationship to the core spec: wai.delivery.ledger is a record (SPEC §5): a signed record a WAI tool emits and verifies. It names no payload format and is not dispatchable.

2. Terms

  • Seller, buyer: Ed25519 keys (RFC 8032). The seller operates the ledger and signs its invoices; the buyer is the customer billed.
  • Holder (version 8): an Ed25519 key that keeps objects for the buyer over time and signs what it kept (§4.13).
  • Time: microseconds since 1970-01-01T00:00:00Z, the unit of a room's t0 (live-rooms §3.1). A period is a span of time from its start (included) to its end (excluded).
  • Minor unit: a currency's smallest unit (ISO 4217); an amount is an integer of millionths of one, as settlement §7.3's amounts are.
  • Source: one record a ledger bills from, with what its own verifier is given (§5).
  • Record identity: the 32 bytes a record of a kind is named by (§5.2).
  • u64, u32, u16, u8: little-endian unsigned integers of that many bits. A digest is SHA-256 (FIPS 180-4), 32 bytes; zero of a key or digest field is 32 zero bytes.
  • Class, tag, unmetered marker: an acquisition class of energy-measurement §2.7, its tag byte (2 ModelBased, 3 Estimator, 4 OnChipCounter, 5 CalibratedInstrument), and a figure of 0 with no class.

3. One tariff across rooms, packages and HTTP delivery

The records a deployment bills from state their units in their own terms. A room-session receipt states microseconds and events (live-metering §4.4), and may state a tariff of its own, which prices the session's grants against their funds ceilings (§4.6 there). A settlement statement states acknowledged bytes by object class, whatever carried them: a relay over MOQT, or a cache over HTTP whose deliveries were acknowledged as settlement §9.1 maps them; it may state a tariff too, which prices its own lines (§7.3 there). A package receipt states entries and bytes (packaging §9) and no tariff. An ad decision's receipt states impressions (live-ads §8.2) and no tariff of the seller's; so does a stream another party stitched, whose stitcher signs a pod-input record, WSI1, of the ads it chose and whose players sign a claim, WSC1, of each ad presented (stitched-presentation §4, §5).

A tariff of this extension prices every one of those units in one currency, so one invoice bills a buyer's rooms, deliveries, packages and ads together. Three rules keep every figure in it consistent with what the records say:

  1. A record that states a tariff states this one. A room-session receipt of a source either states no tariff (currency zero) or the tariff's currency and its room prices, in live-metering §4.1's order: the thirteen, and the price of bytes out, which a receipt of version 1 and a tariff of versions 1 to 3 do not state and read as 0; a settlement statement either states no tariff or the tariff's currency and its four delivery prices, in settlement §7.1's order. A record under another tariff is refused tariff_conflict (§7.2 step 5): the funds its grants were held to, or the amount its party stated, were computed at other prices, and an invoice at these prices would contradict it.
  2. One rounding, the same everywhere. Every amount is a quantity times a price, divided by the unit's divisor and rounded down once per invoice line (§6.4), as settlement §7.3 rounds a statement's line. A statement's own amount rounds once per payer; the invoice rounds once per party and class, so the two can differ by less than one millionth of a minor unit per payer line, and the delivery report (§8.2) states both.
  3. Units are never converted. A room is billed in its own units (in version 4, its bytes out too), a delivery in bytes, a package in packages, entries and stored bytes (in version 4, in byte-days held), an ad in impressions, a job in jobs or in the subpixels its output's receipt states (§4.5), and in version 4 in the work units of the packages it made, and in version 7 a transmission in the octets and the pass time its schedule states (§4.10), an aggregate receipt in its count (§4.11) and an agent's consumption in objects (§4.12), and in version 8 a holder's storage in the byte-seconds its records state, in whole byte-days (§4.13). No line turns one unit into another, and no line is priced from joules: the energy of an invoice is stated beside its lines (§6.6), per class, and is not an amount.

So the tariff is the one place prices live: a room receipt's funds verdicts, a statement's amount and an invoice's lines all follow from it, and a buyer who holds the tariff and the records recomputes all three.

4. The tariff

4.1 Layout

field size meaning
magic 4 WLT1 (ASCII)
version 1 1; 2 for a tariff that prices jobs (§4.5); 3 for one that prices them per operation and bills their work (§4.6, §6.9); 4 for one that also prices bytes out, a package's work and its storage by byte-time (§4.7); 5 for one that holds a decode to its frames (§4.8); 6 for one that also prices a job per endpoint and by a third party's usage, and bills an upscale and a tone mapping (§4.9); 7 for one that also prices a transmission per bearer class, unit and ceiling (§4.10), an aggregated impression (§4.11) and a consumed object (§4.12); 8 for one that also prices storage held over time (§4.13)
seller 32 the seller's key, which signs the tariff and every invoice under it
buyer 32 the buyer's key, which accepts the tariff by signing it
start, end 8 each u64: the period the tariff is good for
currency 3 three capitals A–Z (ISO 4217)
room 52, in version 4 56 thirteen u32: millionths of a minor unit per second of publisher_us, of subscriber_us for each layer class 0 to 8, of composition_us and of recorded_us, and per event sent (live-metering §4.1's order); in version 4 a fourteenth, per 10^9 bytes of bytes_out (§4.7)
delivery 32 four u64: millionths of a minor unit per 10^9 acknowledged bytes of each object class, in class order (settlement §7.1)
package 24, in version 4 8 three u64: millionths of a minor unit per package receipt, per entry, and per 10^9 stored bytes; in version 4 one, per 10^9 byte-days held (§4.7)
ads 16 two u64: millionths of a minor unit per presented impression, and per billable impression
job 2 + Σ (18 + c), in versions 3 and 4 2 + Σ (19 + c + o), in version 6 2 + Σ (21 + c + o + e + u) versions 2 to 4, absent in version 1: a u16 count j, then each job price (§4.5, §4.6, §4.9): cap_len (u8), capability (cap_len bytes), in versions 3 and 4 op_len (u8) and operation (op_len bytes), in version 6 end_len (u8) and endpoint (end_len bytes), then unit (u8), in version 6 use_len (u8) and usage (use_len bytes), then divisor (u64) and price (u64)
transmission 1 + 18 × t version 7, absent before: a u8 count t, then each transmission price (§4.10): bearer (u8), unit (u8), max_bps (u64) and price (u64)
aggregated 8 version 7, absent before: u64, millionths of a minor unit per aggregated impression (§4.11)
consumption 8 version 7, absent before: u64, millionths of a minor unit per object an agent consumed (§4.12)
storage 8 version 8, absent before: u64, millionths of a minor unit per 10^9 byte-days of storage a holder kept (§4.13)
scope 2 + 33 × n a u16 count n, then each entry: kind (u8) and id (32), in strictly ascending order of (kind, id)
seller_sig 64 §4.2
buyer_sig 64 §4.2

4.2 Digest and signatures

The digest of a tariff is SHA-256 over its bytes before seller_sig, the body. Its seller_sig is Ed25519 by seller over the 18 bytes wai:ledger-tariff (ASCII) and 0x01, followed by the body; its buyer_sig is Ed25519 by buyer over the 18 bytes wai:ledger-accept (ASCII) and 0x01, followed by the body. Both are verified strictly, as SPEC §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. The buyer's signature is what binds the buyer to the prices: a tariff the buyer did not sign bills nobody.

4.3 Reading and rules

A reader reads exactly the bytes it is given as one tariff, in the order of §4.1, and refuses at the first of these that holds: fewer than 4 bytes, truncated; a magic other than WLT1, malformed; no fifth byte, truncated; a version other than 1 to 8, unknown_version; the bytes end before a field the layout requires, truncated; bytes after buyer_sig, malformed. It then refuses as tariff_invalid a tariff that breaks any of these:

  • start is below end; currency is three capitals A–Z;
  • seller and buyer are not zero, and not the same key;
  • scope has at least one entry, in strictly ascending order of (kind, id), each kind 1 to 4 (1 to 5 in versions 2 to 6, 1 to 8 in version 7, 1 to 9 in version 8) and each id not zero;
  • in version 2, job has at most 255 prices, each as §4.5 requires, in strictly ascending order of (capability's bytes, unit); in versions 3 and 4, at most 255, each as §4.6 requires, in strictly ascending order of (capability's bytes, operation's bytes, unit); each unit 1 or 2, and in version 4 1 to 3;
  • in version 6, at most 255, each as §4.9 requires, in strictly ascending order of (capability's bytes, operation's bytes, endpoint's bytes, unit, usage's bytes), each unit 1 to 4; and no price of any endpoint beside a price of one for the same capability, operation, unit and usage (§4.9);
  • in version 7, transmission holds prices each as §4.10 requires, in strictly ascending order of (bearer, unit, max_bps), and aggregated and consumption are each at most 2^53 − 1;
  • in version 8, storage is at most 2^53 − 1.

Then the seller's signature, then the buyer's: bad_key, bad_signature.

4.4 Scope

A scope entry names whose records the tariff bills:

kind id a source is in scope when
1 a room id a room-session receipt's room is the id
2 a party's key a settlement statement's party is the id
3 a packager's key a package receipt's signer_pubkey is the id
4 an ad decider's or a stitcher's key every receipt of an ads source has signer_pubkey the id (live-ads §3.4); a stitched source's records are accepted only when their signer is such an id: the verifier's signers (stitched-presentation §7.1) are the scope's entries of kind 4
5 a router's key (versions 2 to 4) a job source's route record has signer the id (route-record §5.1)
6 a publisher's or a node's key (version 7) a group source's group receipt has signer_pubkey the id (jwp-receipts §2.4.1); a cache source's claims do
7 a collector's key (version 7) an aggregated source's receipt has signer the id (telemetry-aggregation §7.1)
8 an agent's key (version 7) a consumption source's claims have signer_pubkey the id (ai-usage §6.1)
9 a holder's key (version 8) a storage source's record has holder the id (§4.13)

The scope is what the buyer agreed to pay for: a record signed by a party the tariff does not name is refused outside_scope (§7.2 step 5), whoever submits it.

4.5 Job prices (version 2)

A tariff of version 2 prices the media jobs a router routed and a hop served. A job price is a capability (route-record §2: 1 to 128 bytes, lowercase ASCII letters, digits, _ and ., beginning wai.), a unit, a divisor of at least 1 and a price: millionths of a minor unit per divisor units of the unit, for a job whose serving hop served that capability. The units are the records' own figures, never converted:

unit name a job's quantity
1 jobs 1
2 subpixels the sum of its output receipts' work_pixel_ops (integer-payloads §15.1): the subpixels its output decodes to
3 work_units (version 4) the sum of its output packages' work_units (packaging §9.1, §4.7)
4 usage (version 6) what its billed hop's third-party record states the provider bills, in the price's own unit (§4.9)

A job the tariff has no price for, by its serving capability, is billed nothing, and a buyer pays for a capability only at a price it signed. A package job stays a package source (§5.1), billed by §4.1's package prices.

4.6 Job prices per operation (version 3)

A tariff of version 3 prices jobs as §4.5 does, and each job price also names an operation: an operation of WAI's catalogue in route-record §2's form (two words joined by ., each a lowercase ASCII letter and then lowercase letters and digits: media.encode, media.decode), of at most 128 bytes. A job is priced by its serving capability and its operation, which is its route record's operation, the one its request named (route-record §5.1). The reason is the work: within one capability, an encode (a motion search, then a codestream written) and a decode (a reconstruction) spend different energy and compute for the same output units, so one price per capability overprices one of them or underprices the other, and a buyer pays each at the price it signed for it. A job the tariff has no price for, by its serving capability and its operation, is billed nothing, as a job whose capability a tariff does not price is (§4.5): a price for one operation never bills another.

Version 3 is a version of its own, not a change to version 2: a reader of version 2 cannot read a job price that names an operation, and the buyer of a version-2 tariff signed version 2's rules. Version 3 also bills a job's work rather than its output's identity (§5.2, §5.3, §6.9). A tariff of version 2, its invoices and its sources read, verify and bill exactly as before.

4.7 Bytes, work and storage (version 4)

A tariff of version 4 prices jobs as version 3 does, and prices three more things by what spending on them scales with:

  1. A room's bytes out. Its fourteenth room price is per 10^9 bytes of a room-session receipt's bytes_out, the payload bytes the hops sent the session's sessions, summed from their ledgers (live-metering §4.4, a receipt of version 2). A room's time units price how long its sessions ran; what delivering them costs scales with the bytes carried too, and a viewer of a high layer and one of a low layer subscribe for the same seconds and are sent different bytes. The receipt states the price in its own tariff and counts it in each grant's funds (live-metering §4.6), so a receipt that states a tariff states this one's fourteen prices (§3). A receipt of version 1 states no bytes, and bills none.
  2. A package's work, per run. Packaging is deterministic: the same source packed again under the same policy gives the same package, under the same receipt, from a run that did the work again with new energy (a customer asks for the work to be done and measured again). So a package is billed as a job is (§6.9): the run that made it is the work, and its receipt is the product, which each run that made it cites. Billing once per receipt refused a package made again, though the work was done again. A run is a job of the catalogue's operation package.build, routed and receipted as any job is (route-record §6): a job source whose output is the package (§5.1), billed at the tariff's job prices for its serving capability and package.build, per job and per work unit: the package receipt's work_units, the work its figure is expressed against (packaging §9.1, jwp-receipts), one per entry, each a base or a refinement the packer coded and wrote, so a price per unit bills what the run spent in proportion to its size. The chain bills each run's route record and hop receipts once, and a run replayed under a new route record is refused (record_rebilled, record_duplicate), as any job's; the package receipt (kind 5) is not billed once, and is cited by each run's line. The run's energy is its hop's figure (§6.6), and the receipt's own figure, the same work's, is not stated again. A package source is the product held: it bills its storage alone (below), never its work, which only a run states.
  3. A package's storage, by byte-time. Its one package price is per 10^9 byte-days: what keeping bytes costs scales with how many are kept and for how long, which a price per stored byte once per receipt ignores. A package whose receipt the previous invoice of the chain lists is held through the invoice's whole period: it was written by the end of that invoice's period, at most this one's start. The invoice bills it ⌊Σ stored_bytes × (end − start) / 86 400 000 000⌋ byte-days over its packager's held packages, the period in microseconds and rounded down once per line, and lists its receipt again. The invoice that first lists a package bills no storage for it: no record shows when within that period it was written, and a buyer pays only for time a record shows the bytes were kept. The period is read from the chain itself, its invoices' start and end, which the seller signs and the buyer holds (§6.9), and the bytes from the package receipt.

A version-3 reader cannot read a tariff of version 4 (its room prices are one longer and its package prices two shorter, and a job price may be of unit 3) or an invoice of version 4 (§6.1: it states a sixth unmetered count), so version 4 is a version of its own. A tariff of versions 1 to 3, its invoices and its sources read, verify and bill exactly as before.

4.8 A decode's output (version 5)

A tariff of version 5 is version 4's in its layout (§4.1), its rules (§4.3), its scope and its prices (§4.4 to §4.7), and an invoice of version 5 is version 4's (§6.1); each bills what version 4 bills. Where this text says version 4, or a range of versions ending at 4, version 5 is included, except as this section says.

A decode (a job whose route record's operation is media.decode) delivers its reconstruction, not a codestream: the codestream is what it read. Version 4 gives every int_motion output as its receipt and its codestream and holds the codestream to what the hop delivered (§5.1), which is true of an encode and false of a decode, whose hop would have to state an object it never delivered and commit its receipt to it (route-record §5.2, §6). Under a tariff of version 5 a decode's output is held to what it delivered:

  1. Each output of a decode's job source is an object of exactly receipt (the text of a wai.video.int_motion decode receipt's JSON form, integer-payloads §15.2), codestream (the WIV1 payload the decode read, hex) and frames (one animated PNG holding its frames, hex). The receipt is read by integer-payloads §15.2 and re-derived from the codestream (§15.1 there): the codestream is the decode's input, and the receipt is the evidence of what it decodes to.

  2. The animation is read whole first: its chunks as packaging §5 reads a still's (every chunk's type four letters and its CRC checked; IHDR first, of 8-bit RGB without interlace; an optional PLTE before the image data; the IDATs consecutive; ancillary chunks read past; any other critical chunk refused; IEND last, empty, and nothing after it), and the chunks of PNG's third edition that make it an animation:

    • one acTL of 8 bytes, before any fcTL and the image data, counting at least one frame, and as many fcTLs as it counts;
    • each fcTL of 26 bytes, of the whole picture (its width and height IHDR's, its offsets 0), its dispose operation 0 to 2 and its blend operation 0, any delay;
    • the first fcTL before the IDATs, so the default image is the first frame, and every other after them, followed by at least one fdAT before the next fcTL or IEND; no IDAT but the first frame's, and no fdAT of it;
    • the sequence numbers of the fcTLs and fdATs 0, 1, 2, … in their order, and every fdAT at least 4 bytes long.

    It is of the receipt's w × h and holds as many frames as the receipt has. Then each frame, in order: its data (the IDATs' for the first frame, its fdATs' after their sequence numbers for each other, concatenated) is read as packaging §5 reads a still's image data, and the frame hash of its samples at its index (integer-payloads §15.1: BLAKE3 over wai:video-rframe, 0x01, the index as a u64 and the RGB8 bytes) is the receipt's frame at that index. Otherwise the source is refused output_invalid: at outputs, the output's index and frames where the animation breaks a rule above or differs in size or count; at outputs, the output's index, frames and the frame's index where that frame's data is not the picture's rows or its samples are not the receipt's; and at outputs and the output's index when the receipt or the codestream does not hold.

  3. The objects the served attempt states it delivered (route-record §5.2) are exactly the decode's animations, by content hash, in the order of its outputs, and nothing else: an animation not stated at its place is refused output_not_delivered at outputs, the output's index and frames, and an object stated past the last, the codestream among them, at outputs. Under a route record of version 3 an animation is at its place when its proof holds it there (§5.1, its index its place), and there is none past the last when the attempt's count is the number of animations.

A decode delivers its frames as one object because a clip's frames are many and repeat: a route record states each of a hop's outputs once, and at most 1024 of them (route-record §5.2), while a clip runs to thousands of frames and a still scene decodes to the same frame again and again. An animated PNG is lossless, one file every browser plays and any tool splits into stills, and its default image is its first frame, which packaging §5's reader of a still reads. The frame hash, not the PNG's bytes, is what the receipt binds, so any writer's animation of the right samples holds; the reference writer is png_still::encode_animation. A frame is the whole picture and its samples replace the picture's, so they are its data alone: a frame blended over the one before, or of part of the picture, would be held to samples its data does not hold.

A decode's billed subpixels are its receipts' work_pixel_ops (§6.3), as in version 4: the receipt states what the frames hold. An encode, and every other job, is held as in version 4. A version-4 reader would read a decode's frames as an unknown member and refuse the source, and a version-4 verdict on a decode must not change under it, so version 5 is a version of its own. A tariff of versions 1 to 4, its invoices and its sources read, verify and bill exactly as before.

4.9 An endpoint, a third party's usage, and what re-derives an output (version 6)

A tariff of version 6 is version 5's in its layout but for its job prices (§4.1), in its rules but for theirs (§4.3), and in its scope and prices (§4.4 to §4.8), and an invoice of version 6 is version 5's (§6.1) but for the records it may list; each bills what version 5 bills. Where this text says version 4 or 5, or a range of versions ending at either, version 6 is included, except as this section says.

A job price names an endpoint. Its endpoint is the endpoint of the attempt it prices, a token of route-record §2's form, or empty, which prices every endpoint. Two providers of one capability have different list prices, so one price per capability overprices one or underprices the other, and a buyer pays each at the price it signed for it. A job is priced as §4.6 prices it and, where a price names an endpoint, by its billed hop's. A price of any endpoint beside a price of one, for the same capability, operation, unit and usage, would bill one job at both, so a tariff that has both is tariff_invalid: its seller states one price for every endpoint or a price for each.

A third party's usage. A job price of unit 4 names usage, a unit of route-record §2's form, and of any other unit none. A job source may give third_party, a list of third-party hop records' texts, which route-record §7.2 step 9 verifies with the rest of its document, a refusal there being the source's. Each record contributes itself (§5.2, kind 17). A job's quantity at a price of usage is the usage.quantity of its billed hop's record, when that record's usage.unit is the price's usage, and otherwise none:

  • a job given no record bills nothing at a price of usage, and bills by its other units;
  • a failed hop's record, and a late hop's, state what the provider billed for it, which is what the router's operator owes the provider, and no line reads it: only the billed hop's usage reaches a line, as §5.1 holds a failed hop's figures from a line;
  • a record's charge reaches no line. It is the provider's own figure in its own terms, and a line adds jobs, so it cannot be summed. The line cites the record, which states it signed, so a buyer reads the two side by side.

A third party's output has no WAI receipt, and a job it served gives no output receipt for it: its record names the objects, and the route record holds them to the hop (route-record §6.2).

An upscale. A job whose route record's operation is media.upscale gives each output as an object of exactly upscale (the text of an upscale record, exact-upscale §4.2), object (the input: a WAI1 of capability wai.image.png holding a PNG of 8-bit RGB that packaging §5's reader reads, hex), prior (the WSR1 it names, hex) and picture (the object the hop delivered: a PNG that reader reads, hex). The record is verified by exact-upscale §7 under require-proof, holding the input, its samples and the prior, and the picture is of the size the record's output is, with the samples whose digest is its output. So what is billed is what the derivation gives: the record's subpixels are the output's width × height × 3, the record contributes itself by its link hash (§5.2, kind 18), and the picture is its object (§5.1). No residual is given, so a record that names one is not proved here. Otherwise the source is refused output_invalid: at outputs, the output's index and object where the input does not read so; at outputs, the output's index and picture where the picture does not read or is not the output; and at outputs and the output's index where the record does not read or is not proved.

A tone mapping. A job whose route record's operation is media.tonemap gives each output as an object of exactly tonemap (the text of a rendition record, exact-tonemap §7.1), envelope (the WAI2 it read, hex) and renditions (each picture's rendition, its RGB16 bytes, exact-tonemap §2, in the record's order, hex), and under a route record of version 3 proofs, in place of proof: one inclusion proof for each rendition (route-record §6.1). The record is verified by exact-tonemap §8 under require-proof, holding the envelope and no decoded frame, so what is proved is a still's pictures, and a record of a video's frames is refused. There is one rendition for each picture, whose digest is the picture's output. So the record's subpixels are its pictures × width × height × 3, and it contributes itself by its link hash (§5.2, kind 19). Otherwise the source is refused output_invalid: at outputs, the output's index, renditions and the rendition's index where a rendition is not its picture's; at outputs, the output's index and renditions where their number is not the record's; and at outputs and the output's index where the record does not read or is not proved. Each rendition is an object the hop delivered, and none is another output's (§5.1): otherwise output_not_delivered, at outputs, the output's index, renditions and the rendition's index. Two pictures of one record may render one picture: the hop states that object once (route-record §5.2), and both are billed, since the record states and proves both.

A job of either operation gives its outputs in that form alone, and any other form is malformed. A job's subpixels (§4.5) sum its output receipts' work_pixel_ops and these records' subpixels. These records are the evidence of what a job delivered, as an output receipt is (§6.9): the derivations are exact, so a run of the same request delivers the same picture, and a later invoice may cite a record again for a new hop's work. Each is a record of the signer that made it, and what its figure rests on is the derivation, which any holder of the source recomputes.

A version-5 reader cannot read a job price that names an endpoint, a job source's third_party, these outputs or kinds 17 to 19, so version 6 is a version of its own. A tariff of versions 1 to 5, its invoices and its sources read, verify and bill exactly as before.

4.10 A transmission on a shared bearer (version 7)

A tariff of version 7 is version 6's in its layout but for three fields after job (§4.1), in its rules but for those fields' and its scope's (§4.3), and in its prices (§4.4 to §4.9), and an invoice of version 7 is version 6's (§6.1) but for its seventh unmetered count and the records, lines and rows of this section and §4.11 and §4.12; each bills what version 6 bills. Where this text says version 6, or a range of versions ending at 6, version 7 is included, except as this section says.

What it prices. A publisher that sends a group over a multicast or unidirectional bearer instance sends it once to every receiver that joins, and learns nothing of who received it (bearer-receipts §2, §3): what the sending spends scales with the octets its passes carry and the time they take, and no record states a quantity per receiver. A tariff of version 7 prices that transmission in the two units a schedule states (carousel §4.1, §5.4): bytes_sent, the octets an entry's passes send, per 10^9 octets, and pass_us, the microseconds of its passes, count × duration_ms × 1000, per 10^6 microseconds. They are rung-price §4.3's transmission units, with its divisors and bounds.

A price for each bearer class, unit and ceiling. Its transmission field holds at most 255 transmission prices, 18 bytes each: bearer (u8), 2 multicast or 3 unidirectional, bearer-receipts §2's classes in their order from 1; unit (u8), 1 bytes_sent or 2 pass_us; max_bps (u64), the ceiling, from 1 to 2^53 − 1 bits per second; and price (u64), millionths of a minor unit per the unit's divisor, at most 2^53 − 1. They are in strictly ascending order of (bearer, unit, max_bps), so a class, a unit and a ceiling have one price. A bidirectional bearer reaches each receiver over its own path and is priced per receiver, by the room and delivery prices, so it has none here. A rung-price list's entry of a transmission unit transcribes into one exactly: its bearer, unit, max_bps and price (rung-price §4.2, §4.3, §7.1).

The tier. An entry of a standing schedule (carousel §6.2 step 4) has a pass rate of ⌈8000 × P / duration_ms⌉ bits per second, P = bytes_sent / count the octets one pass sends, computed in integers wide enough not to overflow (rung-price §7.2). In each unit it is billed at the price of its instance's declared class and that unit whose ceiling is the least at or above its pass rate: the seller's tier that covers it, which the buyer signed. An entry whose pass rate is above every ceiling of its class and a unit has no price in that unit and bills nothing in it, and the report states so (§8.3). So a line at another price of the class and unit, whether at a ceiling below the rate or at one above the least that covers it, states a quantity no record gives at that price, and is refused (§7.2 step 7).

The source. A group source (§5.1) is a group receipt, the object receipts given under it, and its publisher's transmission and schedule claims about it (bearer-receipts §4, carousel §4) in their chain's order, with parent, the text of the claim the first one's parent_receipt_hash names, or null when the first is the head of its chain. A publisher's claims about all its groups are one chain (jwp-receipts §2.4.3), so each group's source names the claim before its own. It is verified as carousel §6.2 steps 1 to 4 verify a group and its claims: the group by jwp-receipts §3 steps 1 and 2; each object receipt against it by steps 4 to 6 with its envelope and step 5 without; parent by jwp-receipts §3.1 steps 1 to 4, then held as its signer's previous claim; each claim by §3.1 steps 1 to 5, then step 6, a transmission claim by bearer-receipts §4.3 and a schedule by carousel §4.3, a claim of another class being context_mismatch; then the declarations and the schedules that stand (bearer-receipts §6.2 step 4, carousel §6.2 step 4), an instance's schedule being the last of a run each of which extends the one before it (carousel §4.5). It is accepted only when all of them are and no claim is set aside: otherwise it is refused with the first refusal's reason, at group, at objects and the receipt's index, at parent, or at claims and the claim's index, and a claim set aside with the reason it is set aside for, at the first such claim. A plan set aside is one the publisher did not hold to, and a source billed in part would bill what it chose.

An entry is billed from the instance's last schedule alone: each schedule that one extends is its first passes (carousel §4.5), and is cited beside it. A schedule that extends one a chain has billed bills no pass twice, since its first pass is in a period already billed and it is in no later one (§5.3). So the passes such a schedule adds are billed by no invoice of the chain, and neither is a schedule whose passes cross a period's end: a schedule is billed whole, in the period that holds it, and a seller sets its periods to hold the plans it bills.

What it contributes. Its group receipt (kind 20) by its link hash (jwp-receipts §3 step 3), and each transmission claim (kind 21) and schedule claim (kind 22) by its link hash. Each instance it declares states its energy once, in scope 7 (§6.6): its declaration's energy, the publisher's figure of transmitting the group on that instance, every repetition included (bearer-receipts §4.1), or the unmetered marker for null. Two declarations of one instance with one body are one, and state the figure once; a declared instance with no schedule bills nothing and states its figure. A bearer instance is one transmission (bearer-receipts §2), so its declaration and its schedule are billed once in a chain, no two sources of an invoice declare one instance of a group (§5.2), and the group receipt is the evidence each transmission of the group cites, listed again by an invoice that bills the group sent on a new instance (§6.9).

A cache's own instance. A node that re-sends, over an instance of its own, objects it holds of a group another key signed declares the instance in a cache-transmission claim (cache-authority §5), may state its plan in a schedule of its own (§5.6 there), and states the bytes of the sending in a declaration of version 2 naming that claim (settlement §4.4). A cache source (§5.1) is the group, the object receipts given under it, the node's claims in their chain's order with parent, and those declarations. It is verified as cache-authority §7.2 steps 1, 2 and 4 verify a group and a node's claims: each cache-transmission claim by §5.3 there, each schedule by §5.6 there, and the instances and schedules that stand as §7.2 step 4 and §5.6 say, every claim the same node's, never the group's key, and a claim of another class or key being context_mismatch, a group source given such a claim refuses it the same way. Each declaration reads (settlement §3.6, with that text's reasons), is of version 2, its upstream the node and its instance the link hash of a claim the source gives, otherwise context_mismatch, at declarations and its index. An instance with an entry to bill and no declaration naming its claim is refused record_missing, at that claim. A cache-transmission claim says what was sent and a schedule what was planned, so an entry is billed only when the claim's bit of its leaf_index is set (cache-authority §7.2 step 6): an object scheduled and not sent bills nothing. It is billed as a publisher's is, at the transmission prices of the instance's class, in the octets and pass time its schedule states, on lines whose source is the node. No line reads a declaration's bytes, which count objects and not their passes: a declaration is the node's statement that it made the sending, in a window the period holds, and bounds no quantity. The source contributes its claims (kind 23), its schedule claims (kind 22), its declarations (kind 4), each of those billed once, and the group receipt (kind 20), which any number of transmissions cite, so a publisher's transmission of a group and a node's own instance of it can be on one invoice. The claim's energy is stated in scope 7 as a declaration's is.

An instance is one party's. A cache source holds the node's claims alone, so cache-authority §7.2 step 4's rule that an instance a publisher declared is no node's own reaches what a verifier is given beside them: a cache source and a group source of one group that declare one bearer_id on one invoice are refused bearer_contradicted at the later of them, and so are two cache sources of two keys that do (§5.2, §7.2 step 6). A verifier given only the node's claims is shown no declaration of the publisher's, and accepts them. The reference ledger holds every source of a chain and applies the rule across them (§9), and a buyer that holds the publisher's claims runs cache-authority §7.2 over both.

Transmission, not delivery. A transmission line bills what a publisher or a node declared it sent, in the octets and the pass time its own schedule planned. It states nothing of any receiver: no line reads a reconciliation (bearer-receipts §5) or a count of receivers, and a transmission line MUST NOT be presented as delivery to anyone (bearer-receipts §6.3, rung-price §7.3).

4.11 An aggregated impression (version 7)

An impression counted over a bearer with no return path is the class aggregated (impression-aggregates §9): a lower bound of what receivers reported, which no presentation claim stands behind. It is priced in a unit of its own, aggregated_impressions, at the tariff's aggregated price per impression, and never under presented_impressions or billable_impressions: an invoice that states such a count under either is refused quantity_not_recorded (§7.2 step 7), since no source gives that line.

An aggregated source (§5.1) is one aggregate receipt, WQA1 (telemetry-aggregation §7). A verifier reads it as data, in this order: the receipt reads (§7.2 there, at receipt); its signer is the collector, whose signature verifies (bad_key, bad_signature, at receipt); its task reads through time_precision (DAP §4.2), the unit its batch is stated in, which is not 0 (task_invalid, at task); the leader's statement reads whole (statement_invalid, at leader, §6.1 there), has the leader's role, 2 (wrong_signer, at leader, §8.1 step 5 there), and states a batch of a duration of at least 1 (batch_invalid, at leader, §8.1 step 7 there); and the elements of result, summed as integers, are its report count (count_mismatch, at result). Its count is that sum. Then, at §7.2 step 5, the tariff names the collector in its scope (kind 7), so the buyer chose whose count it pays on. A holder of the receipt and its catalogue verifies it further by impression-aggregates §8.1, and a verifier of this extension runs no other step of that text: the receipt's count is the collector's word to the buyer that named it.

The source contributes its receipt (kind 24) by its digest (telemetry-aggregation §7.1), and one line of the collector's, its quantity the sum of the counts of its receipts, citing each. A receipt is billed in the period that holds its batch (§5.3), and a chain's periods do not overlap, so a chain bills it once, and a verifier needs no invoice but the one it is given to see that. Two receipts of one task, by their task bytes, whose batches share a time unit are refused: DAP collects a bucket once, and an impression table sets both aside (impression-aggregates §8.2). On one invoice the later is record_overlap (§5.3); on two invoices of a chain one of them is outside_period, since one period alone holds that time unit. A count states no energy (impression-aggregates §9), so the source states no figure. Its line is a count of reports: it is no audience, and a party that shows an invoice beyond the holders of its receipts holds it to impression-aggregates §8.3, a line being a sum over a table's rows.

4.12 An object an agent consumed (version 7)

An agent's use of objects is stated in a consumption claim (ai-usage §6), which the agent signs. A tariff of version 7 prices it per object, at its consumption price, in the unit consumed_objects.

A consumption source (§5.1) is an agent's claims, at least one, in their chain's order, with parent, the text of the claim the first one's parent_receipt_hash names, or null, read as a group source's parent is. Each claim is verified by jwp-receipts §3.1 steps 1 to 5, at claims and its index, and held to the chain by step 5; a claim of another class, or of a key another claim of the source does not have, is context_mismatch. Step 6, ai-usage §6.3, needs the objects, their statements and the room, which the ledger does not hold: a holder of them runs it, and its outcome bills nothing and refuses nothing here. A claim refused at that step is still its signer's statement of what it consumed (ai-usage §6.4). The tariff names the agent in its scope (kind 8), so the buyer pays on the word of an agent it named.

The source contributes each claim (kind 25) by its link hash, and a line of the agent's, its quantity the objects its claims name, one for each object of each claim, an object named by two claims being two uses, citing each claim. A chain bills a claim once. A claim states no energy, so the source states no figure.

A version-6 reader cannot read a tariff with a transmission, aggregated or consumption field or a publisher, a collector or an agent in its scope, a group, cache, aggregated or consumption source, kinds 20 to 25 or an invoice's seventh unmetered count, so version 7 is a version of its own. A tariff of versions 1 to 6, its invoices and its sources read, verify and bill exactly as before.

4.13 Storage held over time (version 8)

A tariff of version 8 is version 7's in its layout but for one field after consumption (§4.1), in its rules but for that field's and its scope's (§4.3), and in its prices (§4.4 to §4.12), and an invoice of version 8 is version 7's (§6.1) but for the records, lines and report of this section; each bills what version 7 bills. Where this text says version 7, or a range of versions ending at 7, version 8 is included, except as this section says.

What it prices. A holder that keeps objects for a buyer beyond their delivery, a stream's recent window a player seeks back into or a clip cut from it and kept, spends on the bytes it keeps and on how long it keeps them. No record this text reads states that: a package receipt states a package's bytes and no time (§4.7), and a window's objects change with each one admitted and each one evicted. A tariff of version 8 prices such storage by byte-days, as version 4 prices a package's, at its storage price: millionths of a minor unit per 10^9 byte-days, at most 2^53 − 1. What it bills from is the holder's own statements, signed as they are made, of what a set listed at each instant its listing changed, and its record of the bytes the set held over an interval, which the verifier recomputes from them.

A stored set is the objects a holder keeps together and states together: a stream's window, which lists the segments a player can reach, or a clip's files. Its subject is 32 bytes the holder names it by and names no other set by, the digest of a name of its own choosing: a set whose objects change keeps its subject, so a window's snapshots over a day, each listing other segments, are of one subject. Its listing at an instant names each object it lists by its content hash, SHA-256 of its bytes, and its length; the listing's digest is SHA-256 over the 19 bytes wai:ledger-listing (ASCII) and 0x01, followed by each object, in strictly ascending order of content hash, as its content hash (32) and its length (u64). So a snapshot binds its bytes to a list of objects, which anyone holding them recomputes, and the listing of no objects is SHA-256 over those 19 bytes alone.

A snapshot, WLS1, is a holder's statement of what one stored set lists at one instant:

field size meaning
magic 4 WLS1 (ASCII)
version 1 1
holder 32 the holder's key, which signs it
subject 32 the stored set it is of
at 8 u64: the instant it states, a time (§2)
objects 4 u32: the objects the set lists at at
bytes 8 u64: their lengths, summed
listing 32 the digest of its listing at at
sig 64 Ed25519 by holder over the 20 bytes wai:ledger-snapshot (ASCII) and 0x01, followed by the bytes before sig

A storage record, WLH1, is a holder's statement of the bytes one stored set held over an interval:

field size meaning
magic 4 WLH1 (ASCII)
version 1 1
holder 32 the holder's key, which signs it
subject 32 the stored set it is of
start, end 8 each u64: its interval, start included and end excluded
byte_seconds 8 u64: the bytes the set held over the interval, in byte-seconds (below)
snapshots 4 + 32 × n a u32 count n, then the digest of each of its snapshots, in the order of their instants
sig 64 Ed25519 by holder over the 19 bytes wai:ledger-storage (ASCII) and 0x01, followed by the bytes before sig

The digest of a snapshot or a record is SHA-256 over its bytes before sig. A reader reads exactly the bytes it is given as one snapshot or one record, as §4.3 reads a tariff, with its own magic, and a version other than 1 is unknown_version. It refuses as storage_invalid one that breaks any of these: holder and subject are not zero; of a snapshot, one of no objects states 0 bytes and the listing of no objects; of a record, start is below end and it names at least one snapshot. Then its signature, verified strictly as SPEC §7 Signatures requires: bad_key, bad_signature.

The rule. A holder states what a set lists when its listing changes, and the bytes listed at an instant are those of the set's latest snapshot at or before it. A record's snapshots therefore cover its interval: the first is at its start, each later one after the one before it, and none at or past its end. Its byte-seconds are what they state, the sum over its interval of the bytes listed at each instant:

byte_seconds = ⌊Σ bytesᵢ × (atᵢ₊₁ − atᵢ) / 10^6⌋,

over its snapshots in order, at in microseconds and atₙ its end, computed in integers wide enough not to overflow and rounded down once per record. A record that states any other figure is refused storage_mismatch. One that claims more bills bytes its holder never said it kept; one that states a set's bytes as its byte-seconds, a quantity of one unit read as another, states a figure its own snapshots contradict, and so does one that states fewer.

The source. A storage source (§5.1) is one record and its snapshots, verified in this order: the record reads and its signature verifies, at record; as many snapshots are given as it names (snapshot_mismatch, at snapshots); each snapshot, in order, reads and its signature verifies, and it is of the record's holder and subject and its digest is the one the record names at its place (snapshot_mismatch), at snapshots and its index; the snapshots cover the interval (outside_interval, at snapshots and the index of the first that does not); and the record's byte_seconds is what they state (storage_mismatch, at record). Then, at §7.2 step 5, the tariff names the holder in its scope (kind 9), so the buyer chose whose word on storage it pays on, and the record's interval lies within the invoice's period (§5.3).

What it contributes. Its record (kind 26) and each snapshot (kind 27), each by its digest and each billed once in a chain (§6.9). Its line is its holder's: the quantity ⌊Σ byte_seconds / 86 400⌋ over the holder's storage sources, byte-seconds into whole byte-days rounded down once per line, as version 4 rounds a package's (§4.7), at the tariff's storage price per 10^9 byte-days, citing each record it counts whose byte_seconds is above 0 and the snapshots each names. A snapshot states no energy, so the source states no figure. A record is billed in the period that holds its interval, and a chain's periods do not overlap, so a set's time is billed once in a chain; two records of one holder and one subject whose intervals overlap on one invoice bill one time twice, and the later is refused record_overlap (§5.3). A holder makes a record of each set for each period it is invoiced by, beginning with a snapshot at the period's start: a record whose interval crosses a period's end is billed by no invoice, as a schedule crossing one is not (§4.10).

Why the holder's snapshots. Every other quantity this ledger bills is a figure of a record its party signed, which the verifier reads or recomputes, and which it places in a period by the time that record states: a room session's microseconds, a statement's period, a batch, a claim's issue. Storage over time is a figure of the same kind, and the holder is its party, as a node is of its own instance (§4.10). A figure signed only when it is billed would be one the buyer could take or leave. Snapshots are signed as the listing changes, each binding its bytes to the objects listed by their content hashes, and the record's figure is a pure function of them, so a buyer given the record and its snapshots recomputes the line, and a record that claims more than they support is refused by any verifier. A package's storage is billed from the chain instead (§4.7): its bytes do not change while it is kept, and its receipt states no time. A window's bytes change by the minute, and neither its objects' receipts nor the chain state them.

What rests on the holder's word. The ledger does not read a listing: it holds a record's figure to its snapshots and each snapshot to its holder's signature. A holder of the objects, the publisher whose segments a window lists, recomputes a snapshot's bytes and listing from them. Whether the holder kept what it listed is its statement, as a package's storage is the seller's (§12).

A version-7 reader cannot read a tariff with a storage field or a holder in its scope, a storage source or kinds 26 and 27, so version 8 is a version of its own. A tariff of versions 1 to 7, its invoices and its sources read, verify and bill exactly as before.

5. Sources

5.1 Kinds and their documents

A source is a JSON object (RFC 8259) whose kind names its extension, holding exactly what that extension's verifier is given. Bytes are lowercase hexadecimal strings.

kind members verified as
room room (descriptor, grants, key_log_head (a string or null), chains, a list of lists of records), receipt, hops (each record and ledger), descriptors, compositions, takes, logs (a string or null) live-metering §5.1, its receipt being receipt
delivery statement, records (each record and its items, one item list per entry), proofs, hops, rooms (each descriptor and grants) settlement §8.2
package receipt (the text of package.receipt.json), indexes (the index files in the receipt's component order) packaging §9, a receipt of version 2 against its indexes
ads descriptor, grants, key_log, chains, policy, pt0_ms, receipts (form-2 receipts in their JSON carriage), pods, claims, creatives, issuers live-ads §9, with ad-presentation §9 under a policy that requires claims
stitched records (pod-input records), claims (stitched claims), manifests, responses (VAST and VMAP documents), receipts (form-1 receipts in their JSON carriage), creatives, issuers stitched-presentation §7, its signers the tariff's (§4.4)
group (version 7) group (a group receipt, jwp-receipts §2.4.1), objects (each receipt, an object receipt, and envelope, its envelope or null), claims (the texts of its publisher's transmission and schedule claims about the group, in their chain's order) and parent (the text of the claim the first one follows, or null) §4.10: carousel §6.2 steps 1 to 4, every claim accepted and none set aside
cache (version 7) a group source's members, claims being the texts of one node's cache-transmission and schedule claims, at least one, and declarations (its WDA1 records of version 2, settlement §4.4) §4.10: cache-authority §7.2 steps 1, 2 and 4, every claim accepted and none set aside, and each declaration naming a claim given
aggregated (version 7) receipt (an aggregate receipt, telemetry-aggregation §7) §4.11: read as data: its collector's signature, its task's time_precision, its leader's statement and its count
consumption (version 7) claims (the texts of an agent's consumption claims, at least one, in their chain's order) and parent (the text of the claim the first one follows, or null) §4.12: jwp-receipts §3.1 steps 1 to 5
storage (version 8) record (a storage record, WLH1) and snapshots (the snapshots it names, WLS1, in its order) §4.13: the record, each snapshot it names, their cover of its interval and its byte-seconds
job (versions 2 to 4) request, pricebook, policy, record, receipts, keys (a route record's verification document, route-record §7.1, its receipts and keys not null) and outputs, a list of objects of exactly receipt (the text of a wai.video.int_motion decode receipt's JSON form, integer-payloads §15.2) and codestream (the WIV1 payload it describes: the object the hop delivered, named by its content hash; in version 5 a decode's output also has frames, the animation of its frames it delivered, and its codestream is what it read, §4.8), or, in version 4, of exactly package (the text of a package receipt of version 2, package.receipt.json: the object the hop delivered) and indexes (its index files in its component order); under a route record of version 3, each output also has proof, its object's inclusion proof (route-record §6.1); in version 6, it may also have third_party, and an upscale's and a tone mapping's outputs have their own forms (§4.9) route-record §7, accepted with its hop receipts checked; then each output receipt read by integer-payloads §15.2 and re-derived from its codestream (§15.1 there), each package verified against its indexes by packaging §9, or output_invalid at outputs and its index, an upscale's and a tone mapping's outputs as §4.9 says; then each output held to what its hop delivered, or output_not_delivered there

A source is accepted when its extension's verifier accepts it; for ads, when the outcome is accept (live-ads §9.4), a gap being source_gap. A stitched source is always accepted, since its verification refuses nothing as a whole (stitched-presentation §7.5): a record it does not accept, of a signer outside the scope among them, bills nothing, and a claim it does not find presented counts nothing. A source that is not such an object, whose kind is none of these, or whose members are not exactly its kind's, each of its form, is refused malformed. Under a tariff of version 1, a job source is not a kind, and is malformed; under a tariff of versions 1 to 6, nor are group, cache, aggregated and consumption sources; under a tariff of versions 1 to 7, nor is a storage source.

A job source's billed hop is the attempt of its route record that is billed (route-record §5.2), if any; its serving capability is that attempt's candidate's capability, its operation is its route record's operation, and its figure is the figure of that attempt's OER/2 receipt: the unmetered marker (oer-receipts §3.1), or energy.joules_total in microjoules, rounded to the nearest and a half to the even one, with the receipt's energy.class. A billed hop's receipt whose figure has no class, or rounds below 1 µJ or past what a u64 holds, cannot be stated in a row (§6.6): the source is refused job_figure_invalid, at receipts and the receipt's index. Under a tariff of version 4 every attempt's figure is stated (§6.6), so the same holds of each attempt that is not billed, a failed hop and one that served past the deadline.

A job's output is the object its hop delivered. An output's object is its codestream, or a package's receipt text, named by its content hash (route-record §2, jwp-receipts §2.1). A route record of version 2 states the objects its served attempt delivered, by content hash, and holds that hop's receipt to them (route-record §5.2, §6). Each output a job source gives is then one of those objects, and no two of its outputs are one object: otherwise the source is refused output_not_delivered, at outputs and the output's index. The reason is the subpixels a line bills (§6.3): they are read from the output receipts, and an output receipt of an object the hop did not deliver bills subpixels nobody delivered for this job, as a receipt given twice bills them twice. So the chain closes: the hop's receipt names its outputs, the record names the hop's receipt and the outputs, and each output receipt is of one of them. Under a tariff of version 5 a decode's object is the animation of the frames it delivered, not the codestream it read (§4.8). Under a tariff of version 4, a record that states no outputs (a record of version 1, or one no attempt served) holds every output to none, and a job it routed is billed by the job alone; under a tariff of version 3, a record of version 1's outputs are read as before.

A route record of version 3 states what its served attempt delivered by its count and root, not by a list (route-record §3.4, §5.2), so a hop may deliver any number of objects. Each output of a job source under one gives proof, the inclusion proof of its object (route-record §6.1), and is one of the objects the hop delivered when its proof holds its object's content hash to the served attempt's count and root; an output under a record of version 1 or 2 gives none. An output without its proof, or with one under a record of version 1 or 2, or a proof that is not an object of exactly an integer index and a list of content hashes' texts, siblings, is malformed; a proof that does not hold is output_not_delivered, at outputs and the output's index, as an object a list does not state is; and no two outputs are one object, as before. The ledger does not hold the count to the objects, which it is not given: the hop's receipt names the root alone (route-record §6). A count stated larger than the objects lets the last of an odd level be proved at a second place, and that place is one object, which no source bills twice; a decode is held to its places and its count (§4.8). Under a record of version 3 no attempt served, the outputs are held to none.

Routing figures are never charges. A route record's candidates' cost, energy, expected_cost and expected_ttfb_ms, and its price book's price and failures, are the router's figures for choosing an endpoint (route-record §4.2, §4.4): what a hop costs the router, and what the failures it measured cost it, per successful job. No line reads them. A job line bills its billed attempt alone, at its list price, the tariff's job price for its serving capability and operation, which the buyer signed: a failed attempt, what a provider billed for it and the expected cost per successful job never reach a line, however the router ranked, and a line that counts a failed hop as a job, or prices one at the router's figures, does not recompute.

5.2 What a source contributes

Each source contributes records, each named by a kind and an identity. This table is the one registry of record kinds: every WAI text that names a record by a kind (in a citation digest, or in a list of records) takes the kind from here, and a new kind is assigned here, the next free one. Kinds 10 to 13 are defined by the texts that cite them and are no ledger source's; the others are the ledger's own:

record kind record identity contributed by
1 a room-session receipt, WMR1 its digest (live-metering §4.2) a room source: its receipt
2 a per-hop record, WMH1 its digest (live-metering §3.5) a room source: each record its receipt names; a delivery source: each record its statement names in hops
3 a settlement statement, WSS1 its digest (settlement §7.4) a delivery source: its statement
4 an acknowledgement or declaration, WDA1 its digest (settlement §3.5) a delivery source: each record its statement names in records; a cache source (version 7): each declaration it gives
5 a package receipt its receipt_hash (packaging §9) a package source; a job source (version 4): each output package
6 a wai.video.ssai receipt of the break form its identity (live-ads §8.4) an ads source: each receipt
7 a presentation claim, WPC1 its digest (ad-presentation §5.3) an ads source: each claim that reads
8 a pod-input record, WSI1 its digest (stitched-presentation §4.4) a stitched source: each record it accepts
9 a stitched claim, WSC1 its digest (stitched-presentation §5.3) a stitched source: each claim that reads
10 a run of a channel's program-as-run its identity (revenue-share §7.4) no source: cited by revenue-share §7.4 and opportunity-report §7.3
11 an invoice, WLI1 its digest (§6.7, as revenue-share §7.4 cites it) no source: cited by revenue-share §7.4
12 a cue event its event digest (opportunity-report §7.3, live-events §3.2) no source: cited by opportunity-report §7.3
13 a room policy its digest (opportunity-report §7.3, live-ads §3.2) no source: cited by opportunity-report §7.3
14 an OER/2 receipt the 32 bytes its receipt_id names (oer-receipts §5) a job source (versions 2 to 4): the receipt of each attempt of its record
15 a wai.video.int_motion decode receipt its receipt hash (integer-payloads §15.1) a job source (versions 2 to 4): each output receipt
16 a route record its digest (route-record §5.3) a job source (versions 2 to 4): its record
17 a third-party hop record its digest (route-record §6.2) a job source (version 6): each record it gives
18 an upscale record its link hash (exact-upscale §2) a job source (version 6): each upscale's record (§4.9)
19 a rendition record its link hash (exact-tonemap §2) a job source (version 6): each tone mapping's record (§4.9)
20 a group receipt its link hash (jwp-receipts §3 step 3) a group or cache source (version 7): its group (§4.10)
21 a transmission claim its link hash (jwp-receipts §3.1) a group source (version 7): each declaration it gives
22 a schedule claim its link hash (jwp-receipts §3.1) a group or cache source (version 7): each schedule it gives
23 a cache-transmission claim its link hash (jwp-receipts §3.1) a cache source (version 7): each claim it gives
24 an aggregate receipt, WQA1 its digest (telemetry-aggregation §7.1) an aggregated source (version 7): its receipt (§4.11)
25 a consumption claim its link hash (jwp-receipts §3.1) a consumption source (version 7): each claim it gives (§4.12)
26 a storage record, WLH1 its digest (§4.13) a storage source (version 8): its record
27 a snapshot, WLS1 its digest (§4.13) a storage source (version 8): each snapshot its record names

Kinds 28 to 127 are unassigned. Kinds 128 to 255 are reserved for private and provisional use: an implementation's own records, such as a hosted service's provisional records carried beside WAI's until WAI defines them, may name records by them, and no kind WAI assigns later will ever be one of them. A WAI record never states one, and a WAI verifier refuses one wherever a WAI record states a kind, private_kind: in this extension, an invoice's records (§6.8). No citation digest WAI defines covers one.

A source's head is its receipt, statement or package receipt; an ads source's heads are its receipts, a stitched source's its accepted records, a job source's its route record, a group source's its transmission and schedule claims, a cache source's its cache-transmission and schedule claims, an aggregated source's its receipt, a consumption source's its claims and a storage source's its record. A head of one source that is a head of another source of the invoice is refused record_duplicate. A record that is no head of a source may be another's: a group receipt is the head of no source (§4.10), and a package receipt is none of the run that cites it (§4.7). A per-hop record, which a room receipt and a statement can both name, is contributed once.

An instance of a group, by the group's link hash and its bearer_id, is one party's one transmission (§4.10), however many claims state it, and two groups on one bearer_id, a broadcast service carrying both, are two instances. A group or cache source that declares an instance an earlier source of the invoice declares is refused, whichever claims each gives: record_duplicate when one key declared both, and bearer_contradicted when two did (cache-authority §7.2 step 4). So no schedule, entry or energy figure of an instance is stated twice.

An OER/2 receipt a job source contributes that an earlier job source of the invoice also contributes is refused record_duplicate too: one hop serves one job, so no hop is billed for two. Under a tariff of version 2, so is an output receipt: one output is one job's. Under a tariff of version 3 or 4 it is not: an output receipt is the evidence of what a job delivered, not the work, and the same request run again on a deterministic codec delivers the same object, of the same content hash, under the same receipt from a new hop that did the work again (§6.9). Two lines of one invoice that cite one output receipt therefore cite different hop receipts, whichever lines they are.

5.3 Placement in time

A source is in a period when:

  • room: the receipt's session, placed by its room's t0, lies within it: t0 + start ≥ the period's start and t0 + end ≤ its end;
  • delivery: the statement's period lies within it;
  • ads: the t of the break each receipt names, placed by the room's t0, is within it;
  • package and stitched: always: a package receipt and a pod-input record state no time, and the chain (§6.9) bills each once; under a tariff of version 4, a package's work once and its storage for the periods it is held through (§4.7);
  • job: its route record's accepted is within it;
  • group: every pass of every entry of its standing schedules is within it: first_ms × 1000 is at least the period's start, and the end of the last pass, (first_ms + (count − 1) × period_ms + duration_ms) × 1000, at most its end. A source with no schedule is in every period;
  • cache: every pass of every entry it bills is within it, as for group, an entry its claim does not say was sent being no pass of the source (§4.10), and each declaration's window lies within it;
  • aggregated: its batch is within it: start × time_precision × 10^6 is at least the period's start, and (start + duration) × time_precision × 10^6 at most its end, start and duration the leader's statement's and time_precision its task's, in integers wide enough not to overflow. The period is when the reports were made, not when their count arrived: a batch is collected after a hold (impression-aggregates §7.1), so a seller invoices a period once the batches it bills are collected, and a batch that crosses a period's end is billed by no invoice;
  • consumption: each claim's issued_at, in seconds with any fraction dropped, × 10^6, is within it: at least its start and below its end;
  • storage: its record's interval lies within it: the record's start is at least the period's start, and its end at most the period's end.

Two room receipts of one room whose sessions overlap, two statements of one party whose periods overlap, two receipts of the invoice's ads sources naming one break and one session, two aggregate receipts of one task whose batches share a time unit (§4.11), two storage records of one holder and one subject whose intervals overlap (§4.13), and, under a tariff of version 2, two route records of one router naming one job, bill one thing twice: the later is refused record_overlap. Under a tariff of version 3 or 4, two route records of one job are two runs of it, each billed from its own hop, and no hop twice (§5.2): a job's id names what was asked, not the work, and a request run again is worked again.

6. The invoice

6.1 Layout

field size meaning
magic 4 WLI1 (ASCII)
version 1 its tariff's version, 1 to 8
seller, buyer 32 each the tariff's
tariff 32 the tariff's digest
prev 32 the digest of the invoice before it in its chain (§6.9); zero for the first
start, end 8 each u64: the period it bills
currency 3 the tariff's
records 4 + 33 × r a u32 count, then each record (§5.2): kind (u8) and id (32), in strictly ascending order of (kind, id)
lines 2 + 94 × l a u16 count, then each line (§6.3), in strictly ascending order of (source_kind, source, unit)
energy 1 + 18 × e a u8 count, then each row (§6.6): scope (u8), tag (u8), figures (u32), joules (u64, µJ), max_ppm (u32), in strictly ascending order of (scope, tag)
unmetered 16, 20, 24 or 28 four u32: the unmetered figures of scopes 1 to 4 (§6.6); in versions 2 and 3, five, scopes 1 to 5; in version 4, six, scopes 1 to 6; in versions 7 and 8, seven, scopes 1 to 7
amount 8 u64: the sum of the lines' amounts
sig 64 §6.7

6.2 Records

records lists every record the sources contribute (§5.2), each once. It is what the invoice was computed from, and what the next invoice of the chain may not bill again.

6.3 Lines

A line is 94 bytes:

field size meaning
source_kind 1 1 room, 2 delivery, 3 package, 4 ads, 5 job (versions 2 to 4), and in version 7 6 group, 7 aggregated, 8 consumption, and in version 8 9 storage
source 32 the room id, the delivering party, the packager, the ad decider, the router, the publisher or node, the collector, the agent or the holder
unit 1 the unit (below)
quantity 8 u64: the quantity of the unit the records state
price 8 u64: the tariff's price for the unit
amount 8 u64: §6.4
cited 4 u32: the records the line cites (§6.5)
cites 32 their citation digest (§6.5)

The units, the quantity each sums over the sources of its source, and the price and divisor of each:

source_kind unit name quantity price divisor
1 1 publisher_us the receipts' publisher_us room 0 10^6
1 2–10 subscriber_us_0–subscriber_us_8 their subscriber_us of layer class unit − 2 room 1–9 10^6
1 11 composition_us their composition_us room 10 10^6
1 12 recorded_us their recorded_us room 11 10^6
1 13 events_sent their events_sent room 12 1
1 14 bytes_out (version 4) their bytes_out, of receipts of version 2 (§4.7) room 13 10^9
2 1–4 live, fetch, fill, ancillary the bytes of the statement's delivery lines of that class that are not free (settlement §7.2) delivery unit − 1 10^9
3 1 packages the number of package receipts package 0 1
3 2 entries their total_entries package 1 1
3 3 stored_bytes their stored_bytes package 2 10^9
3 3 byte_days (version 4, its only package unit) ⌊Σ stored_bytes × (end − start) / 86 400 000 000⌋ over the package receipts the previous invoice lists, which are held (§4.7) package 0 of version 4 10^9
4 1 presented_impressions under a policy that requires claims, the impressions that count (ad-presentation §9.2); of a stitched source, the presentations of its accepted records' ads (stitched-presentation §7.4), one per session ads 0 1
4 2 billable_impressions under a policy that does not, the billable impressions (quartile at least 1) ads 1 1
5 k the k-th job price's unit over the router's job sources with a billed hop whose serving capability is that price's capability (and, in versions 3 and 4, whose operation is its operation, and, in version 6, whose endpoint is its endpoint, when it names one): one per job (jobs), each job's output receipts' work_pixel_ops (subpixels), in version 6 with its upscale and rendition records' subpixels, or, in version 4, its output packages' work_units (work_units), or, in version 6, its billed hop's record's usage in the price's unit (usage, §4.9) the k-th job price's price its divisor
6 k the k-th transmission price's unit, bytes_sent or pass_us (version 7) over the publisher's group sources, or the node's cache sources, each entry of a standing schedule on an instance of that price's bearer that §4.10 bills at that price: its bytes_sent, or its pass_us the k-th transmission price's price 10^9 for bytes_sent, 10^6 for pass_us
7 1 aggregated_impressions (version 7) over the collector's aggregated sources, each receipt's count (§4.11) aggregated 1
8 1 consumed_objects (version 7) over the agent's consumption sources, the objects each claim names (§4.12) consumption 1
9 1 byte_days (version 8) ⌊Σ byte_seconds / 86 400⌋ over the holder's storage records (§4.13) storage 10^9

In version 4 a package source bills only its byte_days, and its work is its run's job line. There is one line for each source and unit whose quantity is above 0, a price of 0 included, and none for a quantity of 0. A delivery line's bytes are those its party's downstream parties signed for (settlement §3.7): a declared byte and a free retrieval are never billed, and the delivery report states both (§8.2). An ad line counts impressions under one rule or the other, never both: a policy that requires claims bills only what the players' own claims show presented, and one that does not bills on the decider's beacons, under a unit of its own.

6.4 Amounts

A line's amount is ⌊quantity × price / divisor⌋, computed in integers wide enough not to overflow, and the invoice's amount is the sum of its lines' amounts. A line amount or a sum past what a u64 holds cannot be stated, and a ledger refuses to compute such an invoice.

6.5 Citations

Each line cites the records it came from:

  • a room line: the receipts of its room whose figure of the unit is above 0;
  • a delivery line: the statements of its party with a delivery line of the class that is not free, and each acknowledgement (mode 1) they name with an entry of the class that is not free (a retrieval class with a zero grant is free);
  • a package line: the package receipts of its packager whose figure of the unit is above 0; in version 4, the held receipts its byte_days count;
  • an ad line: the receipts of its decider with at least one impression counted under the unit, and, for presented_impressions, each counted impression's own claim; of a stitched source, its stitcher's accepted records, and each presented own claim of their ads;
  • a job line: for each job it counts, its route record and its billed hop's OER/2 receipt, and, for subpixels, each of its output receipts whose work_pixel_ops is above 0. In versions 3 and 4, an output receipt that two jobs of the line delivered is cited once and its work_pixel_ops counted for each (§6.9); in version 4, for work_units, each of its output packages whose work_units is above 0, a package that two runs of the line made cited once and counted for each; in version 6, for subpixels, each of its upscale and rendition records, counted as an output receipt is, and for usage, its billed hop's third-party record;
  • a transmission line (version 7): for each standing schedule with an entry the line bills, the group receipt, the schedule's claims and its instance's transmission claims, or, of a cache source, its cache-transmission claims and the declarations naming them (§4.10);
  • an aggregated line (version 7): each receipt it counts (§4.11);
  • a consumption line (version 7): each claim it counts (§4.12);
  • a storage line (version 8): each record it counts whose byte_seconds is above 0, and each snapshot those records name (§4.13).

cited is their number, and cites is SHA-256 over the 17 bytes wai:ledger-cites (ASCII) and 0x01, followed by each cited record's kind and identity, in ascending order of (kind, identity). Every cited record is in records. A buyer recomputes a line from the records it cites alone, and shows one line to an auditor with its records and nothing else. One line is the exception: a job line of version 3 or 4 two of whose jobs delivered one output receipt names each job and that output once, and how many of its jobs delivered the output is stated by their sources, each of which pairs its job with its outputs (§5.1).

6.6 Energy

Each record that states an energy figure states it once, in one scope:

scope figures
1 room_hops the per-hop records named by the room receipts (each restated by its receipt, live-metering §4.5)
2 delivery_hops the per-hop records named by the statements and by no room receipt of the invoice
3 packaging the package receipts' joules_micro and class; in version 4 none: a package's figure is its run's, which the run's hop states (§4.7)
4 ad_decisions the ad receipts' joules_micro and class; a pod-input record states no figure
5 jobs (versions 2 to 4) each job source's billed hop's figure (§5.1): the hop that served the job, in the class its OER/2 receipt states; a job with no billed hop states none
6 unbilled_hops (version 4) each job source's attempts that are not billed (route-record §5.2): a failed hop and one that served past the deadline, each its OER/2 receipt's figure (§5.1)
7 transmissions (version 7) each instance a group or cache source declares, its declaration's or claim's figure, once (§4.10): what transmitting on it spent, every repetition included

A failed hop spent energy and delivered nothing, and a hop that served late spent it and delivered too late: neither is billed, and before version 4 neither appeared in any row, so an invoice's energy for its jobs was less than their hops spent. Version 4 states them in a scope of their own, beside the billed hops' and never summed with them: the jobs' energy is scope 5 and scope 6 together, per class, and what the buyer was billed for is scope 5 alone. No line reads scope 6.

For each scope, unmetered counts its figures that are the unmetered marker, which are in no row and MUST NOT be presented as zero joules. For each scope and each tag among its metered figures there is one row: figures, their number; joules, their sum; and max_ppm, the largest relative_ppm among them for tags 4 and 5, which carry a declared uncertainty, and 0 for tags 2 and 3, which do not. When each figure's error is within its declared relative uncertainty, the sum's is within max_ppm of the sum. A row never sums figures of two classes, and no row sums two scopes: a relay's counter reading, a packager's model and a decider's estimate are three rows, since a sum of a model and a counter reading is neither. A row whose tag is 0 is refused classes_summed, and so is a row whose joules is the sum of the figures of its class and of at least one other class of its scope, while not the sum of its own (live-metering §4.5's rule). A scope's energy is whole when its unmetered is 0 and it has a row, partial when it has an unmetered figure, and none when it has no figure; a partial total MUST NOT be presented as the scope's energy.

6.7 Digest and signature

The digest of an invoice is SHA-256 over its bytes before sig. Its signature is Ed25519 by seller over the 19 bytes wai:ledger-invoice (ASCII) and 0x01, followed by the bytes the digest covers, verified strictly (SPEC §7 Signatures).

6.8 Reading and rules

A reader reads exactly the bytes it is given as one invoice, as §4.3 reads a tariff with WLI1 for WLT1 (truncated, malformed, unknown_version), and refuses as classes_summed an invoice with a row of tag 0. It refuses as private_kind an invoice with a record of a kind 128 to 255 (§5.2), and as invoice_invalid one that breaks any of these:

  • start is below end; currency is three capitals A–Z;
  • each list is in the strictly ascending order §6.1 gives it; each record's kind is 1 to 9 (in versions 2 to 4, also 14 to 16: kinds 10 to 13 are no ledger source's, §5.2; in version 6, also 17 to 19; in version 7, also 17 to 25; in version 8, also 17 to 27);
  • each line's source_kind is 1 to 4 (1 to 5 in versions 2 to 4, 1 to 8 in version 7, 1 to 9 in version 8), its unit a unit of its kind in its version (§6.3; for kinds 5 and 6, at least 1), its quantity and cited above 0;
  • each row's scope is 1 to 4 (1 to 5 in versions 2 and 3, 1 to 6 in version 4, 1 to 7 in versions 7 and 8), its tag 2 to 5 and its figures above 0.

Then the signature (§6.7): bad_key, bad_signature.

6.9 Chains

The invoices of one tariff form a chain: each names in prev the invoice before it, the first names zero, and their periods do not overlap. A ledger keeps one chain per tariff. No record is in the records of two invoices of a chain, but, under a tariff of version 3 or 4, an output receipt (kind 15), under one of version 6 an upscale record and a rendition record (kinds 18 and 19, §4.9), under one of version 7 a group receipt (kind 20), which each transmission of the group cites (§4.10), and under one of version 4 a package receipt (kind 5), which each run that made it cites and each invoice whose period it is held through lists again to bill its storage (§4.7): a record billed once is billed never again, whatever period a later invoice states (a storage record and a snapshot among them, §4.13), and a package receipt, which states no time, is billed in the invoice that first holds it.

What a chain bills once for a job is its work, and its output's receipt is the evidence. A run of a job is a hop that did it: new energy, and a new OER/2 receipt and route record, new on every run. An output receipt is not the work: the codecs are deterministic, so the same request run again delivers the same objects, of the same content hashes, under the same receipt. Under a tariff of version 3 or 4, therefore:

  • the records a chain bills once for a job are its route record and its hops' OER/2 receipts, the billed hop's among them, and in version 6 its hops' third-party records, each of one hop;
  • an output receipt is cited, and carried in its lines' citation digests, but is not billed once: a later invoice may list it again for another job's hop;
  • a re-run whose route record and hop receipt are new is billed, in the invoice that holds it;
  • a source with a hop receipt or a route record the previous invoice holds is refused record_rebilled, and one with a hop receipt an earlier source of the invoice gives is refused record_duplicate (§5.2): a replay of either is never billed;
  • two lines of one invoice may cite one output receipt only under different hop receipts.

Under a tariff of version 2, an output receipt is billed once as well, and a re-run of a job whose output an invoice of the chain holds is refused, as that tariff's buyer signed it. A package keeps its rule in versions 1 to 3: it is billed as a delivered product, once per package receipt, which is a rule of its own and not a job's. In version 4 it has a job's shape: the run that made it is the work, billed once per run, and its receipt the product, cited by each run; its storage is billed for each period it is held (§4.7).

7. Verification

7.1 Inputs

A verifier is given the tariff, the invoice, the invoice its prev names (the previous, or none), and the sources, a list. The ledger's verification document holds them as one JSON object: tariff and invoice (hexadecimal), previous (hexadecimal or null) and sources (§5.1).

7.2 Steps

It runs these steps and stops at the first refusal, which it reports with the reason and where:

  1. The tariff (§4.3), at tariff, or tariff and seller or buyer for a signature: truncated, malformed, unknown_version, tariff_invalid, bad_key, bad_signature.
  2. The invoice (§6.8), at invoice: truncated, malformed, unknown_version, classes_summed, private_kind, invoice_invalid, bad_key, bad_signature.
  3. The binding, at invoice: its tariff is the tariff's digest, and its version, seller, buyer and currency the tariff's: otherwise tariff_mismatch; its period lies within the tariff's: otherwise outside_tariff.
  4. The previous, at previous, when prev is not zero: an invoice whose digest is prev is given (record_missing); it reads and its signature verifies (§6.8, with those reasons); its tariff, seller and buyer are the invoice's (tariff_mismatch); and its end is at most the invoice's start (invoice_overlap).
  5. Each source, in order, at source and its index: it is verified as §5.1 says, a refusal being that extension's reason with that extension's place after the index (an ads gap is source_gap, a storage source's reasons and places §4.13's, and a source that does not read malformed); then it is in the scope (§4.4, outside_scope); a room receipt or a statement that states a tariff states this one (§3, tariff_conflict); and it is in the invoice's period (§5.3, outside_period).
  6. Across sources, at source and the index of the later: a head of two sources (record_duplicate); an instance of a group that an earlier source declares (§5.2, record_duplicate, or bearer_contradicted when another key declared it); a receipt, statement, ad receipt or storage record overlapping an earlier one, or, in version 2, a route record of the router and job an earlier one names (§5.3, record_overlap); and a record that is in the previous invoice's records, in versions 3 and 4 an output receipt excepted, in version 4 a package receipt, in version 6 an upscale or rendition record, and in version 7 a group receipt (§6.9, record_rebilled).
  7. The figures, at invoice, recomputed from the sources as §6.2 to §6.6 compute them and compared in this order:
    1. a line whose source and unit no source gives, or that states a larger quantity than the sources give: quantity_not_recorded, a quantity no signed record covers;
    2. a row that §6.6 calls summed across classes: classes_summed;
    3. a line whose cited or cites is not the records it came from: citation_mismatch;
    4. any other difference (the records, a line missing, a smaller quantity, a price, an amount, a row, unmetered, the amount): invoice_mismatch.

A figure that cannot be held in its field is a difference.

7.3 Outcome

  • refuse: the reason and where.
  • accept: the invoice's digest; the tariff's digest; the currency and the period; the number of records; each line with its source kind, source, unit name (and, for a job line, the job price's capability, in versions 3 and 4 its operation, and in version 6 its endpoint and, for a usage, its usage as usage_unit; for a transmission line, its transmission price's bearer and max_bps), quantity, price, amount and its cited records; each energy row by scope and class label with its figures, joules and max_ppm; each scope's unmetered figures and coverage (scopes 1 to 4, in versions 2 and 3 scope 5, in version 4 scopes 5 and 6, and in versions 7 and 8 scopes 5 to 7); the amount; and the reports of §8, in versions 7 and 8 with §8.3's, and in version 8 with §8.4's.

8. Reports

The reports are computed from the verified sources, as the lines are, and are stated with every accepted invoice. They are not signed: anyone holding the sources computes them, and a verifier compares them.

8.1 Ad decisions against presentation claims

For each ads source, in order: its room, whether its policy requires claims, and each receipt in its list's order, with its identity, decider, cue and session, and each impression's slot, ad_id, price_micros and quartiles_reached, whether it is billable (the decider's beacons: a quartile of at least 1), whether it counts, and its verdict: under a policy that requires claims, presented or the reason its own claim did not count, claim_absent among them (ad-presentation §9.2); under one that does not, beacons. Then the receipt's billable impressions and their spend, budget_spent_micros, the seller's figure; and its counted impressions and their spend, the presented spend (ad-presentation §9.3), the buyer's. Then, over the source: the billable and the counted impressions, the billable and the counted spend, and, for each verdict other than presented, the billable impressions that did not count with it.

So a seller's receipts and a buyer's claims are reconciled from the same signed bytes: what the seller billed, what the players presented, and why each impression that was billed and did not count did not.

For each stitched source, in order, the report is the statement of stitched-presentation §7.5 as that extension's verifier gives it, unchanged: each record's verdict, each ad's presentations, quartiles and presented spend, and, for a checked form-1 response, the receipt's own quartile and spend beside them; each claim's verdict; and the spend by currency, never summed across currencies. That statement is the seller-against-buyer reconciliation of a stitched stream, and the ledger computes no second one.

8.2 Delivery by party

For the delivery sources together, each party in ascending order of key: the digests of its statements; their currency (the stated one, or null); the acknowledged objects and bytes of each class; the free retrieval bytes; the declared declarations, objects and bytes (settlement §4), never billed; the sum of its statements' own amounts; the sum of the invoice's lines of the party; and its energy rows and unmetered figures over its per-hop records.

Then the overlaps: for each pair of acknowledgements (mode 1) of two different parties, signed by one downstream key, whose windows overlap, and each content hash that an item of each names with byte ranges that share bytes, one overlap. It states the content hash, the downstream key, the bytes shared, summed over every such pair of items, and the two parties with their acknowledgements' digests, the lower party first. The overlaps are in ascending order of (content hash, downstream, first party, first record, second party, second record). An overlap is billed by both parties, since each was acknowledged; it is what a buyer using several delivering parties disputes with them, and the report names the signatures it rests on.

8.3 Transmissions (version 7)

For each group and cache source, in order: its group's link hash as group, its publisher or node as publisher, cache, whether it is a cache source, and each entry billed of each of its standing schedules, the schedules in ascending order of bearer_id and each schedule's entries in its order: its bearer_id, its instance's declared bearer, its leaf_index, bytes_sent and pass_us, its pass rate as rate_bps (null above 2^53 − 1, every ceiling's bound), and, as bytes_sent_price and pass_us_price, the index from 1 in the tariff's transmission of the price it is billed at in each unit (§4.10), or null where its pass rate is above every ceiling of its class and that unit. An entry with no price in a unit was sent and is billed nothing in it: the report says which, so a buyer sees what the tiers it signed leave unpriced.

8.4 Storage (version 8)

For each storage source, in order: its record's holder and subject, its interval as start and end, the number of its snapshots, and its byte_seconds. A line sums a holder's records into byte-days, rounded down once; the report states each set's own figure, so a buyer sees what each window and each clip held, and recomputes the line from them.

9. The reference ledger service

wai/wai-ledger runs the ledger as an HTTP service over a directory it owns:

request does
GET /v1 the service, its seller key, its limits
GET /v1/health ok
POST /v1/tariffs {"tariff": hex}: a tariff whose seller is the service's key, both signatures verified (§4), kept by its digest
POST /v1/sources {"tariff": digest, "source": {...}}: the source verified (§7.2 steps 5 and 6 against what the tariff's chain holds), kept by its heads
POST /v1/invoices {"tariff": digest, "start", "end"}: the invoice of the period over the sources held and not yet billed, chained, signed and kept, with its outcome (§7.3)
GET /v1/invoices/{digest} the invoice, its outcome and its verification document (§7.1)
POST /v1/verify a verification document: its outcome

Each refusal names its reason and place. The service writes every file whole (to a temporary name, synced, then renamed), holds a lock on its directory so that one process writes it, and recovers each tariff's chain and held sources from the directory when it starts. A buyer fetches an invoice's verification document and checks it with any verifier of this extension, the service's own not among them.

10. Reasons

The codes this extension adds, each with where it is raised:

reason raised at
tariff_invalid §4.3, §7.2 step 1
invoice_invalid §6.8, §7.2 step 2
tariff_mismatch §7.2 steps 3 and 4
outside_tariff §7.2 step 3
invoice_overlap §6.9, §7.2 step 4
source_gap §5.1, §7.2 step 5
outside_scope §4.4, §7.2 step 5
tariff_conflict §3, §7.2 step 5
outside_period §5.3, §7.2 step 5
record_duplicate §5.2, §7.2 step 6
record_overlap §5.3, §7.2 step 6
record_rebilled §6.9, §7.2 step 6
quantity_not_recorded §7.2 step 7
citation_mismatch §6.5, §7.2 step 7
invoice_mismatch §7.2 step 7
private_kind §5.2, §6.8, §7.2 step 2
output_invalid §4.8, §4.9, §5.1, §7.2 step 5
job_figure_invalid §5.1, §7.2 step 5
output_not_delivered §4.8, §4.9, §5.1, §7.2 step 5
storage_invalid §4.13, §7.2 step 5
snapshot_mismatch §4.13, §7.2 step 5
outside_interval §4.13, §7.2 step 5
storage_mismatch §4.13, §7.2 step 5

A verifier of this extension also raises truncated, malformed and unknown_version for a tariff, an invoice, a snapshot or a storage record that does not read, and malformed for a source that does not read (§5.1); bad_key and bad_signature for their signatures; record_missing (live-metering §9) for a previous invoice not given; classes_summed (live-metering §9) for a row over classes; bearer_contradicted (bearer-receipts §10) for an instance two keys declare across sources (§5.2); and, at a source, every code its extension's verifier raises: live-metering §9 and the codes it lists, settlement §11 and the codes it lists, packaging §12, live-ads §10 with ad-presentation §11, at a job source, route-record §8 and the codes it reuses, at a group source, jwp-receipts §3's and §3.1's codes, bearer-receipts §10's and carousel §9's, at a cache source, those and cache-authority §11's and settlement §3.6's, at an aggregated source, statement_invalid, task_invalid, wrong_signer and batch_invalid (telemetry-aggregation §11) and count_mismatch (age-assurance §7.3), and, at a consumption source, jwp-receipts §3.1's and ai-usage §9's. A stitched source raises none: the codes of stitched-presentation §9 are the verdicts of its records and claims, stated in its report (§8.1).

11. Conformance

live-conformance/ledger/ holds the corpus, in one file, vectors.json, written by wai_receipt_ledger_vectors gen from fixed seeds and from sources taken from the corpora of the extensions it reads (live-conformance/metering/, live-conformance/settlement/, live-conformance/ads/, live-conformance/presentation/, live-conformance/stitched/, live-conformance/routes/ and pack-conformance/packs/), with delivery statements of two parties signed for it and, for each media job, a sink's wai.video.int_motion decode receipt of its output over a payload of wai-rs/tests/vectors/int_video/, and, for version 3, the route records of a decode, a re-run, a replayed hop receipt and a claimed one, routed and sealed under the route corpus's own seeds, as are jobs routed under the route record's version 2, its price book of version 2 with its per-operation entries and measured failures, the served hop stating its outputs, and, for version 7, a broadcaster's groups with their declarations and carousel schedules, a node's own instance of one with its schedule and settlement declaration and an agent's consumption claims, signed for them from fixed seeds, and the aggregate receipts of live-conformance/impressions/, and, for version 8, a holder's snapshots and storage records of a window and a clip over two days, signed for it from fixed seeds. The sources are held once, by name, and each vector is a verification document (§7.1) naming its sources, with the outcome §7.3 gives it:

  • Accepted: an invoice of one day billing a lesson room, two delivering parties and a viewer that forwarded sealed objects under no tariff of its own, a package, ads under a policy that requires claims and under one that does not, with both reports, one viewer acknowledging one object from both parties among the overlaps; the next invoice of its chain, billing a relay's session whose energy is unmetered, and a second package; and an invoice whose room hops are of three classes, one row each; and an invoice of streams stitched by others, one with a form-1 receipt whose own figures the report states beside the presented ones; and, under a tariff of version 2, a month of media jobs one router routed, beside a package: an int_motion job billed per job and per subpixel of its output's receipt, a failover billed at the fallback's price, a job served past its deadline and one every allowed hop failed, which bill nothing, and a job whose serving hop was unmetered, counted unmetered in the jobs' scope; and, under a tariff of version 3, the same jobs priced per operation with an int_motion decode beside the encodes, each at its own price; the next invoice of that chain, billing the first job run again, its route record and hop receipt new and its output receipt one the first invoice holds; the job and its re-run in one invoice, their shared output receipt cited once and its subpixels billed for each; and a decode under a tariff that prices only the encode, which bills nothing; jobs routed under the route record's version 2 billed under version 3 (an encode, a failover billed at the endpoint that served, a decode, a hop past the deadline and three that failed); and, under a tariff of version 4, a lesson room's receipt of version 2 billed by its bytes out beside its time, a package listed and the run of package.build that made it, billed per run and per work unit, and those jobs with every hop's energy, the failed and late hops' in their own scope, one of them unmetered; and the next invoice of that chain, billing the package it holds for the byte-days of its own period and the same package made again by a new run, its work billed again and its receipt cited again, beside a second package listed; and, under a tariff of version 5, an int_motion decode whose served hop states it delivered one animated PNG of the clip's frames, its receipt re-derived from the codestream it read, beside an encode held to its codestream; and jobs whose route records are of version 3, each output proved among what its hop delivered: an encode whose clip is the second of two objects, a decode of version 5 whose animation is its one object, and a package's run whose receipt is the first of 1,501 objects; and, under a tariff of version 6, a third party's jobs billed per job and by what each record states the provider bills, each endpoint at its own price: a served hop, another provider's, a failover whose failed hop's billed usage reaches no line, a job with no record, a job in another unit at that unit's price, and one in a unit no price names; an encode, a decode held to its frames and a package's run, billed as version 5 bills them; an upscale of two pictures and two tone mappings, one of whose records states two pictures of one rendering, each re-derived from what it read; the next invoice of that chain, billing the upscale run again and citing its records again; and an upscale and a tone mapping whose route records are of version 2; and, under a tariff of version 7 that prices multicast octets at two ceilings and pass time at one and broadcast octets at one ceiling and pass time at two, a month of a broadcaster's transmissions in four invoices chained a week apart: a group simulcast on a broadcast and a multicast instance, each entry at the least ceiling covering its pass rate, each declaration's energy in its class's row; a faster broadcast, one entry above every ceiling of its class's octets, billing its pass time alone, beside the first week's group sent again on a new instance, its group receipt listed again; a multicast entry above every ceiling of its class, billing nothing, and a declaration with no figure; a broadcast beside a relay chain declared and scheduled nowhere; and a fifth invoice after the month, billing a broadcast whose schedule a later one extends, a node's own multicast instance of that group with an object scheduled and not sent, the counts of two aggregate receipts whose aggregators state different rejected counts, and an agent's two chained consumption claims; two sources of one group on one invoice, each of an instance of its own; two groups on one broadcast service; an aggregate receipt in the hour its batch fills, and one of statements of version 1; and a node's plan with an entry past the period that its claim does not say it sent, billing what it did; and, under a tariff of version 8, a day of a holder's storage, a stream's window empty at the day's start and then listing three, five and four segments, one snapshot a microsecond after noon so that its byte-seconds round down, and a clip cut at 13:00, on one line of byte-days; the next day of its chain, each set's record from the day's start and the clip's ending at its deletion; that day at a storage price of 0; a record of 1,000 byte-seconds, which bills no line and is listed; and the window's day beside an agent's consumption claims and an aggregate receipt's count, each billed as version 7 bills it.
  • Refused: each reason of §10 at least once, each vector a control of one defect; a source of each kind outside the scope, a room receipt and a statement under other prices, and a source of each timed kind outside the period; a refusal of each source kind by its own extension; and, for version 2, job prices out of order, a router in a version-1 tariff's scope, a job source under a version-1 tariff, a version-1 invoice under a version-2 tariff, a job given twice, routed twice, and claiming another job's output, and a job line and a jobs row that do not recompute; and an invoice of each version listing a record of a kind reserved for private use, and one listing another text's kind; and, for version 3, job prices out of order by operation, a version-2 invoice under a version-3 tariff, a hop receipt the previous invoice billed brought again under a new route record, and one hop receipt claimed by two jobs billed on two lines; and, under a tariff of version 2, the same re-run, refused because its output receipt was billed; and, for a job routed under the route record's version 2, an output receipt of a clip its hop did not deliver and one output given twice (output_not_delivered); and, for version 4, a price of bytes other than the receipt's and a receipt of version 1 under a price of bytes (tariff_conflict), bytes out above the receipt's, storage billed for a package first listed, a held package's storage over the tariff's period rather than the invoice's, a package's run replayed under a new route record in the next invoice (record_rebilled) and in the same one (record_duplicate), a failed hop billed as a job and a job line at the router's list price, the unbilled hops' energy left out or added to the billed hops' row, an unbilled hop whose figure states no class (job_figure_invalid), an output of a route record of version 1, and an invoice of version 3 under a tariff of version 4; and, for version 5, a decode whose record states the codestream it read, and one whose record states it after the animation (output_not_delivered), a decode in version 4's form (malformed), a frame with one sample changed, two frames swapped, a still for the animation, a frame missing, frames of another shape holding the same samples, a codestream not the receipt's, and an animation that blends a frame over the one before, disposes of one by no defined operation, holds a frame of part of the picture, skips a sequence number, keeps its default image apart from its frames, counts a frame more than it holds, or has a frame with no data (output_invalid), a decode in version 5's form under a tariff of version 4, and an invoice of version 4 under a tariff of version 5; and, for jobs routed under the route record's version 3, an output without its proof, a proof under a record of version 2 and a proof whose index is text (malformed), a proof of another place, one past the count, one a sibling short, an output its hop did not deliver, one output twice, a decode's animation at another place, a decode with an object past its animation, and an output of a job no hop served (output_not_delivered); and, for version 6, job prices out of order by endpoint, a price of any endpoint beside one, a price of usage naming no unit, a price per job naming one, an endpoint not of its form and a unit past usage (tariff_invalid); a price of usage under version 5, and an invoice of version 5 listing a third-party record (invoice_invalid), and an invoice of version 5 under a tariff of version 6; a job given third-party records, and an upscale and a tone mapping in version 6's form, under version 5 (malformed); another job's record (third_party_mismatch); a failed hop's usage added to a line, a usage line for a job with no record, and subpixels above a record's (quantity_not_recorded); a usage at another endpoint's price and a record left out of the invoice's (invoice_mismatch), and a usage line not citing its records (citation_mismatch); an upscale whose picture is altered, of another shape or not a PNG, under another prior, of another input, whose input is not an envelope, of another capability or not RGB, whose record states another output, names a residual or does not verify (output_invalid), whose picture its hop did not deliver or given twice (output_not_delivered), in an encode's form (malformed); and a tone mapping with a rendition altered, one missing, renditions out of order, of another envelope, whose record does not verify (output_invalid), with a rendition its hop did not deliver or given twice (output_not_delivered), a proof short, without its proofs, with proofs under a list, or in an encode's form (malformed); and, for version 7, transmission prices out of order, one ceiling priced twice, a price of a bidirectional bearer, a unit past pass_us, a ceiling of 0, a ceiling and a price past 2^53 − 1, and a publisher in a tariff of version 6 (tariff_invalid); an invoice of version 6 listing a group receipt (invoice_invalid) and one under a tariff of version 7 (tariff_mismatch); a group under version 6 (malformed); a line at a ceiling below its entry's pass rate, one at a dearer ceiling than the least that covers it, and an entry above every ceiling billed (quantity_not_recorded); the transmissions' rows left out and an unmetered transmission left out (invoice_mismatch); a line not citing its declaration (citation_mismatch); a publisher outside the scope, a group outside the period, a group given twice and a declaration billed again; and, by the texts a group source is verified by, a schedule contradicted, one with no declaration, one on a relay chain, declarations contradicted, a schedule of another group, a chain not held and one broken, a group receipt altered, and an object receipt of another group; an aggregated count stated under presented_impressions and under billable_impressions, one above its receipts' count, a node billed an object it did not send and a consumption line above its claims (quantity_not_recorded); a collector and an agent outside the scope, overlapping batches on one invoice and on two of a chain, a receipt billed again in the next invoice and two invoices on, a batch a microsecond before and past its period and one past any instant, a schedule extended after it was billed, a claim issued at the period's end and one in the year 0000, a node's declaration outside the period, and a node's entry past the period that its claim says it sent; one schedule and one instance of a node's in two sources, one instance of a publisher's in two sources of its group (record_duplicate), and a node naming the publisher's instance, before and after the group's source, and two nodes naming one (bearer_contradicted); a node's instance with no declaration, with one of another claim or key, its claims and schedules contradicted or undeclared, signed by the publisher or by another key, or given a publisher's claim; an aggregate receipt that does not read, of a version not defined, with its signature failing or its result not its count; a task cut short and one of no precision (task_invalid); a leader's statement of another magic, of a version not defined at either version's length, of version 2's length stating version 1, of no role, a byte short and a byte over (statement_invalid), of the helper's role (wrong_signer) and of a batch of no time (batch_invalid); a consumption source of two agents, of another class, of no claim, without its parent or after another claim; each of the three kinds under version 6 (malformed); and an aggregated and a consumption price past 2^53 − 1 (tariff_invalid); and, for version 8, a record stating a byte-second more than its snapshots support and a clip's record stating its bytes as its byte-seconds (storage_mismatch); a line a byte-day above its records and a clip's bytes billed as byte-days (quantity_not_recorded), and a storage line of a second unit (invoice_invalid); a second record of the window overlapping the day's in one invoice (record_overlap), and, in the next invoice, a record reaching back into the day before, the first day's record again, and that day's records in another day (outside_period); a snapshot an hour after its record's interval, a first snapshot after its start and two out of order (outside_interval); a snapshot whose bytes were raised after it was signed, a record whose byte-seconds were, and a snapshot signed as a record (bad_signature); a snapshot left out, another of the set at the instant of the one named, one of another set and one of another holder (snapshot_mismatch); a record of no time and a snapshot of no objects stating bytes (storage_invalid); a record a byte short (truncated), of a version not defined (unknown_version), a snapshot given as a record, a snapshot with a byte after its signature and a source with no snapshots (malformed); a record given twice (record_duplicate); a holder outside the scope; a storage line not citing its snapshots (citation_mismatch) and a snapshot left out of the invoice's records (invoice_mismatch); a storage price past 2^53 − 1 and a holder in a tariff of version 7 (tariff_invalid); a storage source under version 7 (malformed); an invoice of version 7 listing a storage record (invoice_invalid); and an invoice of version 7 under a tariff of version 8 (tariff_mismatch).

wai_receipt_ledger_vectors verify and the test tests/receipt_ledger.rs check that the file regenerates byte for byte, that wai-rs gives every vector its outcome, that every reason of §10 refuses a vector, and that §10 lists exactly the reference's codes. live-conformance/receipt_ledger_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), verifies each source with that corpus's own second implementation (live_metering_verify.py, settlement_verify.py, live_ads_verify.py with ad_presentation_verify.py, stitched_presentation_verify.py, route_record_verify.py, upscale_verify.py, tonemap_verify.py, carousel_verify.py and cache_authority_verify.py with jwp-conformance/jwp_verify.py and claim-conformance/claim_verify.py, telemetry_aggregate_verify.py's reader of a receipt, and pack-conformance/pack_verify.py) and each output receipt by _int_motion_receipt.py, written from integer-payloads §15, computes each output's content hash with BLAKE3 written from its specification (claim-conformance/_blake3.py), recomputes every line, citation, row and report itself, gives every vector the same outcome, and requires every mutated copy of the corpus to fail.

12. Security and privacy considerations

  • Who signs what. The buyer signs the prices and the scope; each record's own party signs its figures; the seller signs the invoice. A seller cannot bill a unit at a price the buyer did not sign, a record of a party the buyer did not name, or a quantity no record states: the verifier recomputes every line.
  • Double billing. A head is billed once in an invoice (record_duplicate), so is an instance of a group (§5.2), one session, one statement period, one viewer's break and one stored set's time once (record_overlap), and a record once in a chain (record_rebilled). An aggregate receipt and a batch sharing a time unit with it are in one invoice of a chain at most, by their period (§5.3). An instance's claims are billed once in a chain; a party that declares one instance again in a new claim for a later period gives a record no invoice holds, which a verifier given one invoice bills for that period's passes alone, its energy figure stated again, and which the reference ledger, holding every source of the chain, refuses (§9). A verifier given one invoice checks it against the one before it; a buyer holding the chain checks every link.
  • Work, not identity. Under a tariff of version 3 a job is billed for the work done, its route record and its hops' OER/2 receipts, once per chain, and its output's receipt is the evidence of what it delivered (§6.9). A deterministic re-run does the work again, a new hop, new energy, a new receipt, and is billed; a replayed hop receipt or route record is refused, which is what keeps a job from being billed twice. A seller cannot bill a job again by citing its output again: every billing needs a hop receipt no invoice of the chain holds. What a re-run rests on is that hop's receipt: a router and a hop that collude can bill a re-run that never ran, as a party and a downstream key can bill bytes (settlement §13). Whether a request is worked again or answered from outputs still kept is the router's decision, not the ledger's; the ledger bills what was worked. A tariff of version 2 keeps billing an output once.
  • Bytes, work and storage. Under a tariff of version 4 a room's bytes out rest on its hops' ledgers, which each hop signs by their root (live-metering §3.4), as its time rests on their records; a package's work rests on the run that made it, its route record and its hop's receipt, new on every run, and on its receipt's work units, which its indexes recompute; and its storage on the chain: a package is billed a period's storage only when the invoice before lists it, so it was written by the start of the period billed, and a buyer holding the chain sees each period billed once. Whether the seller kept the bytes through the period is the seller's statement, as a delivery is the acknowledging parties' (settlement §13).
  • A third party's usage. Under a tariff of version 6 a job may be billed by what a third party's record states the provider bills. That figure is the router's statement: no provider signs anything, so the record holds what the router read, with the provider's response kept where it was JSON and every byte named by digest (route-record §6.2), and a router can state a usage the provider did not bill. A buyer holds the price it signed and the record the router signed, each line cites that record, and the provider's own charge is stated beside it, so a dispute is about a signed figure; it is not recomputable, as a re-derived subpixel is.
  • What re-derives an output. Under a tariff of version 6 an upscale's and a tone mapping's subpixels are recomputed by the verifier from the record, what it read and what the hop delivered. That binds the picture to its input, and nothing binds the input to what the buyer asked for: the hop's receipt names its inputs by digest, which a holder of them checks.
  • Transmission, never delivery. Under a tariff of version 7 a transmission line rests on the publisher's own declaration and schedule (bearer-receipts §4, carousel §4): what it planned to send and says it sent, which no receiver signs, as a declaration is a party's own word (settlement §4.2). The pass rate that picks a price is a pure function of the signed schedule, and its octets are recomputed from the schedule's parameters, so a seller cannot bill a faster rate's octets at a slower tier's price. What the passes reached is a reconciliation's (bearer-receipts §5), which no line reads. A node's line rests on its own claim, plan and declaration in the same way, and an object it scheduled and does not say it sent bills nothing. Its declaration is evidence that it stated the sending, and no line is held to its bytes (§4.10). An invoice holds an instance to one party across its own sources, and what a verifier is not given it does not read: a buyer holding the group's other claims runs cache-authority §7.2 over them.
  • An aggregated count is the collector's word. Under a tariff of version 7 a line of aggregated_impressions rests on the signature of a collector the buyer named, on a receipt the buyer is given. The ledger holds its result to its count and bills it once; it does not run impression-aggregates §8.1, which needs the receipt's catalogue, so a collector that signs a receipt no aggregator stood behind is found by a holder running that text, not by this one. That check is the buyer's to run, with the receipt the source gives it.
  • A consumption line is the agent's word. It rests on a claim an agent the buyer named signed. The ledger does not check the claim against the objects and their statements (ai-usage §6.3), so a line bills a use whether the governing statements allowed it or not, and says nothing of that.
  • Storage is the holder's word, held to itself. Under a tariff of version 8 a storage line rests on a holder the buyer named, on snapshots it signed as a set's listing changed and on records it signed over intervals. The verifier recomputes every record's byte-seconds from its snapshots, so a holder cannot bill more time or more bytes than its own snapshots state, nor bill one set's time twice in a chain. It does not see the objects: a holder can sign snapshots of bytes it did not keep, or of a listing it did not have, as a seller can state a package kept that it deleted (§4.7). A holder of the objects recomputes each snapshot's bytes and listing from them, and a dispute is about a signed statement. A holder that signs no snapshot when its listing changes bills the bytes of its last one until its next, more or less than it kept: the buyer that names it accepts its cadence.
  • Every hop's energy. Under a tariff of version 4 an invoice states the energy every hop of its jobs spent, the hops the buyer was not billed for in a scope of their own, so a seller whose router fails often shows it in the energy it states, and is not paid for it.
  • What the figures rest on. An invoice is as true as its records: a delivery line rests on acknowledgements, so a party and a downstream key that collude can bill bytes that never moved, as settlement §13 says; a room line rests on per-hop records and the room's events; an ad line under claims rests on players' session keys. The reports name the signatures each figure rests on, so a dispute is about records, not about logs.
  • Energy. A row states figures as their parties signed them, with their class: it is attributable and its sum recomputable, not true (energy-measurement §5). max_ppm bounds the declared part of a sum's uncertainty and says nothing of a class's undeclared systematic error.
  • What an invoice reveals. Its records list names every record by identity, and its lines name rooms, parties, packagers and deciders. A verification document holds the records themselves: acknowledgements name downstream keys, and ad receipts name sessions. They travel between the seller, the buyer and an auditor they choose; the service serves an invoice's document by its digest and lists nothing.