wai.delivery.settlement (E6): a hop is paid only for bytes the next hop signed for #404
Loading…
Reference in a new issue
No description provided.
Delete branch "wai/settlement"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
wai.delivery.settlement(E6): a hop is paid only for bytes the next hop signed forDelivery settled on what the party that received it signed, not on the sender's own logs.
What is in it
wai/extensions/settlement.md, which registers the recordwai.delivery.settlement:Acknowledgement
WDA1(§3). The downstream party (a next hop or a sink) signs what it received in a window. Each entry covers one object class (live,fetch,fill,ancillary) under one grant and one proof. It states the objects as the tree root of jwp-receipts §2.2 (unlabelled leaves, so a whole group in order gives the publisher's root), and gives a count, a byte count and the SHA-256 of the item list. The item list travels beside the record: content hash, start, end. Records of one (mode, upstream, downstream) form a chain: windows do not overlap, andprevnames the record before. A relay acknowledges upstream and is acknowledged downstream over the same content hashes. A hop's billable bytes are exactly the bytes its downstream parties signed for. An acknowledgement whose downstream is its own upstream is refused (self_acknowledged).Unacknowledged delivery (§4). A hop whose downstream will not or cannot sign uses a declaration: the same layout with mode 2, signed by the hop. It is counted in its own class,
unacknowledged: never zero, never billed, and never covering a byte the same party acknowledged in an overlapping window (declared_and_acknowledged). Bearers: "a unidirectional bearer settles under unidirectional-delivery §4", with no duplication of T2's work.Range proof
WBR1(§5). It carries the covered chunks of a range plus the chaining value of every subtree of BLAKE3's chunk tree that lies outside them, and it verifies to the content hash. It generalises http-delivery §6's head proof, whose ranges start at 0. A proof establishes the object's length only when it reaches the last chunk (a tail proof), and the verifier reports whether it did. §5.6 defines audits: an auditor names an acknowledged item and asks for a proof of a range within it.Paid retrieval (§6). A fetch below the live edge, a recording fetch, or a fill past a cache is billed only to a room grant whose
WRP1proof the request carried. Each entry is checked against live-rooms §10.5.4 steps 2–5, the grant's window and the seek power, and one proof pays for one record (pop_replayed). A retrieval made without a grant is free, and a statement that bills it is refused (paid_without_grant).Statement
WSS1(§7). One per party per period. It holds:WMH1records, never summed across classes (classes_summed);The verifier recomputes every figure. A line that bills bytes no acknowledgement covers is
bytes_not_acknowledged; any other difference isstatement_mismatch. Line kind 2 is reserved for a payee that is not a hop (the CO6 slot), withpayeeandpayeralready in the line layout. This revision refuses it.Logs (§9). Each acknowledged item maps onto an RFC 7937
cdni_http_request_v1record (cdni_http_request_v2under RFC 9246), with the acknowledgement's digest in aremarkdirective. §9.2 states what a log cannot carry: a counter-signature. Each log record is the writer's own word, andSHA256-hashis the writer's own integrity hash. A log therefore maps onto declarations, never onto acknowledgements. §9.3 covers SVTA2050, SVTA2007 and SVTA2006, cited by identifier only. Only their published summaries could be read, and the text says so.Viewers as relays over ciphertext (§10, built). An acknowledgement binds the content hash of the sealed bytes, so a forwarder that cannot open what it forwards earns acknowledged bytes and can prove ranges of them. The corpus has one such statement and one sealed range proof.
§11 is the reasons table (19 codes). §13 states what an acknowledgement reveals and to whom, with no gate of its own (per the owner rule). A regime that asks the operator for a lawful basis is pointed at the
lawful-basisdeclaration (jwp-receipts §2.4.6).wai-rsmodulesettlement(featuresettlement = ["live_metering", "jwp_hash"], no new dependency). It has the records, the range proof via blake3'shazmatAPI (as the head proof uses it), grant and proof checks vialive_room,WMH1vialive_metering,verify, and unit tests. It also has the generatorwai_settlement_vectorsandtests/settlement.rs.wai/live-conformance/settlement/, written from fixed seeds:48 statements. Five are accepted:
The rest are refused, each a control of one defect. They include every negative the brief named: billing bytes no acknowledgement covers, an acknowledgement signed by the hop itself, a paid fetch without a grant, joules summed across classes, a statement that does not recompute, and an acknowledgement replayed from another period.
24 range proofs. Accepted cases include an interior range, the head, the tail (length established), one chunk, whole objects, a sealed object, an answered audit, and an interior range under a wrong length that leaves the tree's shape unchanged (accepted, length not established). Refused cases include a range past the end, an empty range, bytes of another object, a range past the true end under a longer length, a chaining value dropped, added or changed, another content hash, an audit outside its item, and records that do not read.
live-conformance/settlement_verify.py, run aspython3 -I. It shares no code with wai-rs. It reuses BLAKE3 fromclaim-conformance/_blake3.pyby import (the pattern exists: itssubtree_cvandparent_cvare the head proof's tree), strict Ed25519 from_ed25519.py, andlive_rooms_verify.py/live_metering_verify.pyfor rooms, grants, proofs andWMH1. It requires every mutated copy of the corpus to fail, and drops each of its own 29 checks in turn, requiring the corpus to catch each one.wai-conformance.yml, with the extension added topaths:;REGISTRY.mdrecord list,SPEC.md§5 (record list and paragraph) and theCHANGELOG.mdentry;codecs/registry.rs(CAP_DELIVERY_SETTLEMENT, and the wire identifiersWDA1§3.1,WBR1§5.2,WSS1§7.1), with the registry export regenerated;int_kernels_vectors.rsexclusion reason forlive-conformanceextended to settlement;**Provenance.**line, andlive-conformance/README.md.Design decisions and why
WMH1spans are placed with their room'st0, read from the descriptor the verifier is given.Checks (all cargo work ran on the build host via
rb)cargo run --no-default-features --features settlement --bin wai_settlement_vectors -- gen/verify ../live-conformance/settlementcargo test --no-default-features --features settlement --lib settlement::cargo test --no-default-features --features settlement --test settlementcargo clippy --no-default-features --features settlement --all-targetsunpinned_readdead code, which also appears with--features live_meteringalone)python3 -I live-conformance/settlement_verify.py live-conformance/settlementlive_events,live_rooms,live_metering,energy_steering,ai_usage,live_moderation_verify.py, andhttp_verify.pycargo run --no-default-features --bin wai -- registry exportthen--check;cargo test --lib codecs::registrycargo test --no-default-features --test corpus_provenance --test cli_registry;--test int_kernels_vectors every_decoded_output_states_a_sha256(CI feature set)check-tests-in-ci.py,check-workflow-concurrency.sh,check-spec-refs.py,check-wai-section-refs.py,check-no-vanity-metrics.sh,test-public-text-checks.sh,check-comparative-prose.sh,check-orphan-sources.pyNot run:
check-public-names.sh, which needs the privateWAI_NAME_DENYLIST. CI runs it.Falsifications (committed first, then broken on the host and restored)
self_acknowledgedcheckcargo test --test settlementexit 101bytes_not_acknowledgedcheckthe_extension_lists_the_reasonsfails, andsettlement_verify.pyexits 1 ("18 reasons")After restoring, exit 0. The Python verifier's own drop-each-check loop first found two checks the corpus did not exercise: item-list overlap, and a proof whose
content_hashfield names another object. Two vectors were added for them (items_share_a_byte,names_another_content_hash).Not done
🤖 Generated with Claude Code