open-standards/wai/wai-ledger
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Transaction Science 0e4487a921
Some checks failed
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 8s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 18s
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (push) Successful in 45s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 1m34s
joule-code conformance gate / Build + round-trip C1-C4 vectors (push) Successful in 3m27s
joule-code conformance gate / joule-moq-relay, every target (push) Successful in 3m57s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 4m44s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 5m26s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 5m29s
joule-code conformance gate / joule-moq-ingest, every target (push) Successful in 6m26s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 6m51s
wai-audit collector and player integration / does this change touch it (push) Has been cancelled
wai-audit collector and player integration / collector · linux (push) Has been cancelled
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Has been cancelled
WAI operation catalogue / does this change touch it (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
wai-quantum docs, course and locales / does this change touch it (push) Has been cancelled
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Has been cancelled
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Has been cancelled
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Has been cancelled
wai-quantum for JavaScript / does this change touch it (push) Has been cancelled
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
wai-quantum studio and desktop / does this change touch it (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · windows (push) Has been cancelled
wai-sink-android native sink library / does this change touch it (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
wai-sink-swift native sink package / does this change touch it (push) Has been cancelled
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Has been cancelled
WAI Studio / does this change touch it (push) Has been cancelled
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 9m33s
wai release binaries build on Windows / the seven release binaries · windows (push) Successful in 12m21s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 12m37s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 14m48s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Has been cancelled
joule-moq-room room service / joule-moq-room · does this change touch it (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
wai-app and Create / wai-app · does this change touch it (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Has been cancelled
wai-fleet service / does this change touch it (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
wai-fleet service / service · macos (push) Has been cancelled
wai-key-proxy / does this change touch it (push) Has been cancelled
wai-key-proxy / proxy · linux (push) Has been cancelled
wai-ledger service / does this change touch it (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
wai-ledger service / service · macos (push) Has been cancelled
wai-int-module WAISM module of record / does this change touch it (push) Successful in 11s
wai-int-module WAISM module of record / the module of record in Chromium (push) Successful in 10s
wai-int-module WAISM module of record / linux · both checkers, wasmtime (Cranelift, Winch), Wasmi and Node (push) Successful in 9m8s
wai-int-module WAISM module of record / linux-arm64 · both checkers, wasmtime (Cranelift, Winch), Wasmi and Node (push) Successful in 6m56s
wai command line release / the tag is the crate's version (push) Successful in 16s
wai command line release / the room client and WAI Studio (push) Successful in 3m21s
wai command line release / macOS · aarch64-apple-darwin (push) Successful in 9m15s
wai command line release / Linux · x86_64-unknown-linux-musl (push) Successful in 12m56s
wai command line release / Linux · aarch64-unknown-linux-musl (push) Successful in 13m24s
wai command line release / macOS · x86_64-apple-darwin (push) Successful in 21m33s
wai command line release / Windows · x86_64-pc-windows-msvc (push) Successful in 28m22s
wai command line release / Homebrew formula and Scoop manifest (push) Successful in 9s
wai 0.6.0
The crate's version for the release wai-v0.6.0, version only: wai/wai-rs/Cargo.toml and the
`wai` entry of the eighteen lockfiles that hold it; the installer's default
(wai/quickstart/install.sh), which the release's first job requires to be the tag's version;
the catalogue export, whose `toolchain` is the crate's version, and WAI Studio's actions
generated from it (node scripts/actions.mjs). The changelog's entries under wai/changes/ are
assembled into it (scripts/changelog-assemble.py --write) and become v0.6.0, under an
Unreleased heading for what comes next. Fixtures and recorded measurements keep the version
they name.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-09 16:17:06 -05:00
..
src Tariff version 7 bills an instance once and a batch in one period, reads the leader's statement whole, and its service issues the month 2026-11-07 08:35:01 -05:00
Cargo.lock wai 0.6.0 2026-11-09 16:17:06 -05:00
Cargo.toml Six WAI services answer GET /metrics, and wai-audit builds as a library 2026-11-07 01:50:40 -05:00
README.md Tests hold what a restarted ledger and fleet state before any write, and every route each router declares to its pattern 2026-11-07 01:50:41 -05:00
smoke.sh wai-ledger: the receipt ledger as a service; registry, SPEC §5, CHANGELOG and CI 2026-10-25 21:41:30 -04:00

wai-ledger

The WAI receipt ledger (extensions/receipt-ledger.md) as a service. A seller and a buyer both sign a tariff. The ledger verifies each record it is given by the extension that defines it: a room's session receipt, a delivering party's settlement statement with the acknowledgements its downstream parties signed, a package receipt with its indexes, an ad room's receipts with the players' presentation claims. For a period, it signs the invoice whose every line cites the records it came from, with the joules those records state per scope and per acquisition class, and two reports: the ad decisions against the presentation claims, and the delivery of each party with the bytes two parties were acknowledged for twice.

Every invoice is served with its verification document: the tariff, the invoice, the invoice before it in its chain, and the sources. Any verifier of the extension checks it without this service, the corpus's second implementation among them:

python3 -I ../live-conformance/receipt_ledger_verify.py --document document.json

Payments and tax are not here: an invoice is the figures a payment rests on.

Running it

cargo build --locked --release
WAI_LEDGER_DIR=/path/to/ledger WAI_LEDGER_KEY=/path/to/seller.key WAI_LEDGER_ADDR=127.0.0.1:8251 \
  ./target/release/wai-ledger serve
variable meaning
WAI_LEDGER_DIR the directory the service owns (required); created when absent
WAI_LEDGER_KEY the seller key's file: 32 bytes, the Ed25519 seed; made with mode 0600 when absent
WAI_LEDGER_ADDR the address it listens on (default 127.0.0.1:8251)

wai-ledger key prints the seller key of WAI_LEDGER_KEY, which a buyer's tariff names as its seller. wai-ledger verify FILE prints a verification document's outcome.

The directory:

LOCK                                  held exclusively while a process serves the directory
tariffs/<digest>/tariff.wlt           the tariff, both signatures
tariffs/<digest>/sources/<n>.json     the sources held, in the order they arrived
tariffs/<digest>/invoices/<n>.wli     the chain, in order
tariffs/<digest>/invoices/<n>.json    each invoice's verification document

Every file is written whole: to a temporary name, synced, renamed into place, and its directory synced. On start the service takes the lock (a second process on the same directory is refused), then reads every tariff, source and invoice back and verifies each again, and refuses to start on a chain that does not link.

Endpoints

GET /v1 the service, its seller key and its limits
GET /v1/health ok
POST /v1/tariffs {"tariff": <hex>}: a tariff whose seller is the service's key, both signatures verified; 201 and its digest
GET /v1/tariffs/{digest} the tariff, its chain of invoices, and the sources held and not yet billed
POST /v1/sources {"tariff": <digest>, "source": {...}}: the source verified by its extension, in the tariff's scope, under no other tariff, within the tariff's period, and checked against every source held (record_duplicate, record_overlap) and every record billed (record_rebilled); 201 and the records it holds
POST /v1/invoices {"tariff": <digest>, "start": <µs>, "end": <µs>}: the invoice of the period over the sources held, not yet billed, that lie in it (a package always does), chained after the last, signed, verified and kept; 201, the invoice, its outcome with the reports, and its verification document
GET /v1/invoices/{digest} the invoice, its outcome and its verification document
POST /v1/verify a verification document: its outcome
GET /metrics the service's counters in the text exposition format (../wai-metrics): requests by route, method and status (wai_ledger_requests_total), the tariffs, sources and invoices held, and the verifications running. No tariff, party, key or client is a label. It is the operator's, not an operation of the extension: a request that came through a front is answered 404, and a front that sets no forwarding field is configured not to pass the path on

A refusal is 422 with {"outcome": "refuse", "reason", "at"}, the extension's reason and place; a source refused by its own extension names that extension's reason and its place after "source". A body that is not what the endpoint takes is 400; an unknown tariff or invoice is 404. A request body is at most 64 MiB. Requests that change the ledger run one at a time; POST /v1/verify and GET /v1/invoices/{digest} verify at most two documents at a time.

The service has no accounts: a tariff binds a buyer by the buyer's own signature, and a source is accepted only when it verifies and the tariff's scope names its party, whoever submits it.

Checks

cargo test --locked --release          # the corpus's invoices issued byte for byte, the chain
                                       # recovered after a restart, each source billed once,
                                       # one process per directory
bash smoke.sh http://127.0.0.1:18251   # over HTTP, against an instance started with the corpus's
                                       # seller key (see .github/workflows/wai-ledger.yml)