receipt-ledger: tariff version 6 prices an endpoint and a third party's usage, and bills an upscale and a tone mapping by what re-derives them #591

Merged
dcharlot merged 1 commit from wai/tariff-v6-b into main 2026-11-03 02:26:57 -05:00
Owner

Tariff and invoice version 6, specified in extensions/receipt-ledger.md §4.9. It does three things, in one version so a buyer signs one new tariff and not three:

  1. A job price names an endpoint. Two providers of one capability have different list prices, so one price per capability overprices one of them or underprices the other. A price can name an endpoint, or none for every endpoint.
  2. A third party's hop is billed by its usage. A new job unit, usage, takes what the hop's record states the provider bills (route-record §6.2), at that endpoint's price for that unit.
  3. An upscale and a tone mapping are billed by what re-derives them. Their outputs get their own forms. Each record is proved by its own extension's verifier from what it read, and what the hop delivered is held to what that proves.

Decisions a reviewer should check

  • A price of any endpoint beside a price of one, for the same work, is refused (tariff_invalid). It would bill one job at both. The alternative, the specific price winning, would mean a buyer has to work out which price applied.
  • Only the billed hop's usage reaches a line. What a provider billed for a failed hop is what the router's operator owes. It's stated in that hop's record and no line reads it.
  • A record's charge isn't on the line. This drops an earlier proposal. A line adds jobs, and a provider's figure is a string in its own terms, so it can't be summed. The line cites the record, which states it signed.
  • Upscale and tone mapping records can be cited again by a re-run, as an output receipt can. The work billed once is the route record and the hop's receipt.
  • The upscale form has no residual, because nothing produces one yet. A record that names one isn't proved here, so it's refused.

What it can't prove

  • A usage is the router's statement. No provider signs anything. The record keeps what the router read, with the provider's response where it was JSON and every byte named by digest, but a router can state a usage the provider didn't bill. Spec §12 says so. It isn't recomputable the way a subpixel is.
  • Nothing binds a re-derived output's input to what the buyer asked for. The verifier proves the picture came from that input, and the hop's receipt names the inputs by digest for a holder of them to check.

What ran

  • Corpus: 120 → 169 vectors. wai_receipt_ledger_vectors verify regenerates it byte for byte and gives every vector its outcome.
  • Rust tests: tests/receipt_ledger.rs 8 passed, including a new one pinning version 6's figures; the module's unit tests passed.
  • Second implementation: receipt_ledger_verify.py agrees on all 169, using upscale_verify.py and tonemap_verify.py to re-derive independently. It refuses all 183 mutated copies of the corpus, and the corpus catches it with each of its 51 checks dropped.
  • Mutations of the Rust code: 42 of 42 caught, run on the corpus as committed. The first pass caught 39. The three misses were gaps in the corpus, not bugs in the code, and each now has a control:
    • nothing tested a price in another unit beside a price of any endpoint;
    • a control for a unit past usage was refused by a different rule first;
    • only the upscale form had a control under version 5.
  • wai breaking: nothing unacknowledged. The breaking additions are listed in the changelog.

Not run: the mutation run predates this branch's rebase onto main, which moved the commit and changed none of its files' content. The full cargo test on every workspace is left to CI.

Debug test time: CI runs the ledger test in a debug build. It takes 11m29s with this change and 11m57s without on the Framework, the latter while another job was running, so it adds no measurable time.

Follows this: media.upscale and media.tonemap are priced by name here, and #578 adds them to the catalogue with their commands. waiTransport then re-pins, moves to WAI's third-party record in place of its provisional one, and offers tariff version 6.

This replaces #579, whose branch could not be updated in place: the same commit, rebased onto main after #578 merged (CHANGELOG was the only conflict). Retested after the rebase: receipt_ledger_verify.py (every case, 183 mutated copies, 51 dropped checks), the lib's ledger and route-record tests (23) and tests/receipt_ledger and tests/route_record (8 each).

🤖 Generated with Claude Code

Tariff and invoice version 6, specified in `extensions/receipt-ledger.md` §4.9. It does three things, in one version so a buyer signs one new tariff and not three: 1. **A job price names an endpoint.** Two providers of one capability have different list prices, so one price per capability overprices one of them or underprices the other. A price can name an endpoint, or none for every endpoint. 2. **A third party's hop is billed by its usage.** A new job unit, `usage`, takes what the hop's record states the provider bills ([route-record](wai/extensions/route-record.md) §6.2), at that endpoint's price for that unit. 3. **An upscale and a tone mapping are billed by what re-derives them.** Their outputs get their own forms. Each record is proved by its own extension's verifier from what it read, and what the hop delivered is held to what that proves. ## Decisions a reviewer should check - **A price of any endpoint beside a price of one, for the same work, is refused** (`tariff_invalid`). It would bill one job at both. The alternative, the specific price winning, would mean a buyer has to work out which price applied. - **Only the billed hop's usage reaches a line.** What a provider billed for a failed hop is what the router's operator owes. It's stated in that hop's record and no line reads it. - **A record's `charge` isn't on the line.** This drops an earlier proposal. A line adds jobs, and a provider's figure is a string in its own terms, so it can't be summed. The line cites the record, which states it signed. - **Upscale and tone mapping records can be cited again by a re-run,** as an output receipt can. The work billed once is the route record and the hop's receipt. - **The upscale form has no residual,** because nothing produces one yet. A record that names one isn't proved here, so it's refused. ## What it can't prove - **A usage is the router's statement.** No provider signs anything. The record keeps what the router read, with the provider's response where it was JSON and every byte named by digest, but a router can state a usage the provider didn't bill. Spec §12 says so. It isn't recomputable the way a subpixel is. - **Nothing binds a re-derived output's input to what the buyer asked for.** The verifier proves the picture came from that input, and the hop's receipt names the inputs by digest for a holder of them to check. ## What ran - **Corpus:** 120 → 169 vectors. `wai_receipt_ledger_vectors verify` regenerates it byte for byte and gives every vector its outcome. - **Rust tests:** `tests/receipt_ledger.rs` 8 passed, including a new one pinning version 6's figures; the module's unit tests passed. - **Second implementation:** `receipt_ledger_verify.py` agrees on all 169, using `upscale_verify.py` and `tonemap_verify.py` to re-derive independently. It refuses all 183 mutated copies of the corpus, and the corpus catches it with each of its 51 checks dropped. - **Mutations of the Rust code:** 42 of 42 caught, run on the corpus as committed. The first pass caught 39. The three misses were gaps in the corpus, not bugs in the code, and each now has a control: - nothing tested a price in another unit beside a price of any endpoint; - a control for a unit past `usage` was refused by a different rule first; - only the upscale form had a control under version 5. - **`wai breaking`:** nothing unacknowledged. The breaking additions are listed in the changelog. **Not run:** the mutation run predates this branch's rebase onto main, which moved the commit and changed none of its files' content. The full `cargo test` on every workspace is left to CI. **Debug test time:** CI runs the ledger test in a debug build. It takes 11m29s with this change and 11m57s without on the Framework, the latter while another job was running, so it adds no measurable time. **Follows this:** `media.upscale` and `media.tonemap` are priced by name here, and #578 adds them to the catalogue with their commands. waiTransport then re-pins, moves to WAI's third-party record in place of its provisional one, and offers tariff version 6. This replaces #579, whose branch could not be updated in place: the same commit, rebased onto main after #578 merged (CHANGELOG was the only conflict). Retested after the rebase: `receipt_ledger_verify.py` (every case, 183 mutated copies, 51 dropped checks), the lib's ledger and route-record tests (23) and `tests/receipt_ledger` and `tests/route_record` (8 each). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
receipt-ledger: tariff version 6 prices an endpoint and a third party's usage, and bills an upscale and a tone mapping by what re-derives them
All checks were successful
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (pull_request) Successful in 1m34s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 12m30s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (pull_request) Successful in 22m48s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 18m55s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 21s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 55s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 11m30s
wai-fleet service / service · macos (pull_request) Successful in 35s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 24m43s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 36m14s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 10m27s
wai-ledger service / service · macos (pull_request) Successful in 51s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 5m47s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 1m59s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 8m14s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 27m33s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 3m7s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 3m41s
wai-pack / wai-pack · macos (pull_request) Successful in 9m35s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 4m17s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 5m23s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 2m4s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 50m58s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 2m38s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 10m2s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 10m15s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 12m0s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 7m44s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 40m4s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h45m21s
8a409172f9
Two providers of one capability have different list prices, and one price
per capability overprices one or underprices the other. A job price now names
an endpoint, or none for every endpoint. A price of any endpoint beside a
price of one is refused: it would bill one job at both.

A third party's hop is billed by what its record states the provider bills
(route-record §6.2), in a new unit, `usage`, at the price of its endpoint and
its unit. Only the billed hop's record reaches a line: what a provider billed
for a failed hop is what the router's operator owes, and no line reads it. A
record's `charge` reaches no line either, since a line adds jobs and a
provider's figure is in its own terms; the line cites the record, which
states it signed. The proposal to put it on the line is dropped.

An upscale and a tone mapping get their own output forms. Each record is
proved by its own extension's verifier from what it read, and what the hop
delivered is held to what that proves, so the subpixels billed are what the
derivation gives. Their records are evidence, as an output receipt is, and a
new hop's run may cite them again.

These three moves share one version, so a buyer signs one new tariff and not
two. The tariff of versions 1 to 5 reads and bills as before.

The corpus's `invoice_version` control used version 6 as unknown, and now
uses 7. The fixtures are small enough that the corpus's debug test takes as
long as it did without them, about 11.5 minutes on the Framework, and the
README's commands use a release build, which regenerates it in about a minute.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!591
No description provided.