wai: one-way delivery — timeliness, rung price, cache authority and impression aggregates #633

Merged
dcharlot merged 1 commit from wai/one-way-delivery into main 2026-11-05 06:22:49 -05:00
Owner

What this is

Four WAI extensions for one-way delivery: when an object is of use and whether it was held in time (timeliness), what delivering a rung costs (rung price), who served what a node holds and on whose authority (cache authority), and ad presentations counted with no return path (impression aggregates). They come in that order, the order they build on each other.

Merge order. This branch sits on #632's commit, 946f3beda, which moves changelog entries into wai/changes/ and the conformance workflow's lists into step files. Merge #632 first; until it merges, this pull request's diff also shows #632's change. The pull request of wai/ad-consent-supply-chain is stacked on this one.

What it carries. One commit, 793ed1f2d: the change of wai/one-way-delivery (f1258784d..987625394) in #632's layout. Its message lists the source commits. Compared with the source branch:

  • its four changelog entries are four files of wai/changes/, each holding the text the source branch added to wai/CHANGELOG.md;
  • its edits to wai-conformance.yml are step files of .github/wai-conformance/verifiers/: timeliness.sh, rung-price.sh, cache-authority.sh and impression-aggregates.sh, each with its feature and the extension path it reads, and the takedown step's prose edit goes into takedown.sh;
  • in codecs/registry.rs the new rows sit beside the rows they build on instead of at the end: the rung-price wire rows above the route-record rows, IMPRESSIONS beside TELEMETRY_AGGREGATION and RUNG_PRICE just before ROUTE_RECORD. The rows are the same; only their place changed.

Every other file is as the source branch has it.

Each part gets the same supporting changes:

  • a registry row in codecs/registry.rs, with REGISTRY.md, registry/capabilities.json and vocab/v2.ttl regenerated by wai registry export;
  • a SPEC §5 paragraph and a changelog entry file;
  • a step file that runs the module's tests and its second implementation. Its features: line puts the feature into WAI_FEATURES, the --test list and the features-alone lists, and its paths: line puts the extension into the workflow's trigger, through #632's derivation.

Each corpus is written from fixed seeds by its generator, and none is edited by hand.

1. Timeliness (wai.delivery.timeliness, extensions/timeliness.md)

What it defines. This is a publisher's signed statement, for each object of a group, of when the object is of use. It states:

  • the instant the object is useful from;
  • the deadline by which a receiver must hold it for its full value;
  • how that value falls after the deadline, as a stated piecewise-linear function in parts per million that reaches 0 at its end;
  • the rendition a receiver presents in its place, which is a separate object derived from the primary.

The statement is a jwp-receipts claim of class timeliness (§2.4.17), signed by the group's key beside the group receipt, one statement for every bearer.

A verifier reads holdings records, which are a holder's signed word that it held an object at an instant. From them it judges each object for each holder as a sink deciding at the deadline would present it: on time, replaced by its fallback, held only after the deadline and at what value at least, or not shown. Every instant is an upper bound on arrival, so every value is a lower bound. An asker can also plan each object from an instant it states. It goes over its sources in its own order (a carousel's passes, a neighbour's holdings, the origin) and gets the first source that is on time, the fallback, or the best late source.

The deadline is mapped onto parameters the bearers already define, and WAI defines no transport. delivery-telemetry gains the switch reason not-held-by-deadline. A layer of a stage set has no entry and is not a fallback, because staged-delivery alone decides whether a layer is late.

The reference. The timeliness module of wai-rs, with the class's body in claim_receipt::timeliness. wai_timeliness_vectors verify and tests/timeliness.rs check that:

  • the corpus regenerates byte for byte;
  • wai-rs gives every case its stated outcome;
  • every reason and every verdict outcome occurs;
  • the extension's reason list is exactly the code's;
  • jwp-receipts lists the class's codes at their steps.

The independent verifier. live-conformance/timeliness_verify.py is written from the extension alone and shares no code with wai-rs. It uses the JWP, claim, carousel and holdings corpora's second implementations for what those texts define. It writes the rest itself: the checks against the group, the value function, the judging and the planning. It reads the reason codes and outcomes from the text. It requires every mutated copy of the corpus to fail. It drops each of its own checks in turn and requires the corpus to catch each weakened verifier. It also checks the arithmetic at its extremes directly.

Beside it.

  • claim_verify.py reads the new class. It also lists not-held-by-deadline. Before, the two claim verifiers disagreed about a session that switches for that reason, and the claim corpus now holds such a session. It is appended after every other vector, and a test pins the corpus before it.
  • http_receipts.py holds a timeliness claim in a receipt index to its group, as wai-rs does. Before, it accepted one without checking.

2. Rung price (wai.delivery.rung_price, extensions/rung-price.md)

What it defines. This is a seller's signed list of what it charges to deliver a rung. Each price is for:

  • a direction;
  • a bearer class;
  • a footprint of region codes;
  • a ceiling on the rung's rate;
  • a unit, priced at the divisor of the ledger field that bills it.

The energy the seller states sits beside each price. A seller's latest list stands alone, and a list that lapses brings back none of the earlier ones. §2 is WAI's one definition of a region code. It lives in the ungated region module, and other extensions cite it.

A comparer's request removes the options its limits remove and ranks the rest by cost or by energy per receiver. A shared transmission's cost is divided by the audience the comparer states, or by one, and never by an assumed audience. The plan states the audience at which sharing costs no more, and the neighbour order an asker of holdings takes from it. A list is a quote: a buyer is billed only at a tariff it signed, and §7 says which tariff field bills each unit.

Energy ranked by checked evidence. An earlier revision of this part ranked energy by the class a seller stated, and nothing tied the class to evidence. A seller that labelled its figure as calibrated outranked an honest model-based one, and the ranking ignored the declared uncertainty. Now:

  • an entry above the estimate class names, by digest, the seller's own per-hop records whose rate its figure is;
  • an entry of a hardware class states its uncertainty;
  • a comparer given those records holds them to five rules, in order: each record is a relay's, of the seller's own key, and of the entry's class; the entry declares their largest uncertainty; and the figure is their rate, rounded up;
  • the request states which (key, class) pairs the comparer has confirmed, and how old the evidence may be.

Each candidate's evidence is then refuted, absent, outside its window, unconfirmed, or checked:

  • a refuted figure is set aside;
  • only a checked figure ranks at its class, and any other figure ranks as an estimate;
  • a key confirmed for another class confirms nothing;
  • a hardware figure is compared one declared uncertainty above itself;
  • a damaged copy of a record refutes nothing.

A plan names the evidence it read. §10 states that a record's age is only its room's word.

The reference. The rung_price module of wai-rs. wai_rung_price_vectors verify and tests/rung_price.rs check that:

  • the corpus regenerates byte for byte;
  • every case gets its outcome;
  • every reason occurs, and the extension lists exactly the code's;
  • every limit, decision, evidence verdict and energy rank occurs.

Both implementations check the size bounds that no vector carries, and the evidence-text bound is tested on both sides of each of its edges.

The independent verifier. live-conformance/rung_price_verify.py is written from the extension alone and shares no code with wai-rs. It reads:

  • documents with route-record's second implementation;
  • per-hop records with live-metering's;
  • room descriptors with fleet's;
  • signatures with the shared strict Ed25519 check.

It writes the region code, the list rules, the verdicts and the comparison itself, and requires every mutated copy of the corpus to fail. Its weakened verifiers include the defect fixed above, a stated class deciding the rank, and also key-only confirmation, each uncertainty ordering and each edge of the evidence window. The corpus holds the attack on an honest model-based figure in each of its forms.

3. Cache authority (wai.delivery.cache, extensions/cache-authority.md)

What it defines. A node's operator gives the caches and peers it runs two authorities in its key log: the role cache/serve and the class authority cache-transmission. Under the role, a key signs its holdings records and its declarations, and it is the upstream its receivers acknowledge. Neither authority lets the key author, transform or sign a publisher's statement.

A relying party places a server key by the key-log heads it names, in jwp-receipts' three levels:

  • a revoked key is refused;
  • a retired key past its until is refused;
  • a head that lists the key with no serving role refuses it;
  • a key that no head lists is unconfirmed;
  • a head that cannot be read confirms nothing.

A placement labels a server and never changes a verdict.

The cache-transmission claim (jwp-receipts §2.4.18) is a node's declaration that it sent, from what it held, objects of a group another key signed, over a multicast or unidirectional instance of its own. The claim carries a bitmap and a root under the publisher's tree, which are checked without the bytes. It is refused when the group's own key signs it, or when the instance is two-way. The bearer verdict credits a cache per instance, only for what it says it sent, and a cache's instance never makes a group transmitted.

Held by a deadline. A relying party states a population of receiver keys for a region. The count is how many of those keys held an object by a deadline, on their own signed word: acknowledgements, counted reconciliations, or holdings records. The miss rate is in parts per million, rounded up, and every unknown is a miss. §9 derives timeliness lines from all three kinds of statement. Timeliness' own verdict still reads holdings records alone.

The reference. The cache_authority module of wai-rs, with the class's body in claim_receipt::bearer. wai_cache_authority_vectors verify and tests/cache_authority.rs check that:

  • the corpus regenerates byte for byte;
  • every case gets its outcome;
  • every reason occurs, and the extension lists exactly the code's.

The independent verifier. live-conformance/cache_authority_verify.py is written from the extension alone and shares no code with wai-rs. It uses the JWP, claim, bearer, settlement, signer, timeliness and rung price corpora's second implementations for what those texts define. It writes the placement, the claim's checks against its group, the verdict and the count itself. It requires every mutated copy of the corpus to fail and the corpus to catch each weakened verifier, and it checks the population bound directly. claim_verify.py cache-authority reads every claim through steps 1 to 4.

Beside it.

  • Takedown reads a cache-transmission claim as its signer's word that it held what it sent. takedown_verify.py now does too. Before, it failed the committed takedown cases that carry such a claim.
  • Settlement places a serving node by cache/serve.
  • The receipt-index check of http-delivery holds a cache-transmission claim to its group in both implementations. Before, the second implementation accepted one without checking.

4. Impression aggregates (wai.delivery.impressions, extensions/impression-aggregates.md)

What it defines. This part counts ad presentations over a bearer with no return path, as measure 5, impressions, of telemetry-aggregation. A receiver judges each shared stitched ad it presented by stitched-presentation's rules. It turns each presentation into one Prio3Histogram report of creative × region × quartile. It defines three formats:

  • a catalogue (WIC1), which fixes which index is which, bound as the task's scope;
  • a task file (WIT1), whose signer the receiver confirms under its pinned key log with the new pinned-only authority aggregate/task, so a task key can be revoked over the bearer;
  • an upload file (WIU1), which relays forward unchanged.

One-way delivery shapes the rest:

  • a report is generated once, stored and re-sent until it is settled, and never regenerated;
  • a duplicate is discarded by its id;
  • the leader holds each collection for the catalogue's hold, and the aggregators keep the task until its retention instant, so late reports still count;
  • a report later than that is lost, so a count can be lower than what was presented, never higher;
  • with attestation, each report carries a token bound to its task and its report id.

A reader verifies a receipt against its catalogue and recomputes a table of presentations and quartile counts per creative and region. The table is a lower bound on reported presentations. It is never an audience, and never billed as presented. Its totals are exact, and a receipt given twice counts as checked when either copy was. The shared changes to telemetry_aggregate keep every corpus they touch byte for byte.

The reference. The impression_aggregate module of wai-rs. wai_impression_aggregate_vectors verify and tests/impression_aggregate.rs check that:

  • the corpus regenerates byte for byte;
  • every case gets its outcome;
  • every reason occurs, and the extension lists exactly the code's;
  • each standing receipt's result is the plaintext tally of the contributions its reports came from;
  • stitched-presentation's own verification gives the same per-creative counts.

The file size bounds are tested at exactly the bound and at one byte over it.

The independent verifier. live-conformance/impression_aggregate_verify.py is written from the extension alone and shares no code with wai-rs. It evaluates Prio3 and opens reports with the QoE corpus's second implementation. It judges claims with stitched-presentation's, verifies tokens with ad-presentation's, and confirms task-file signers with the signer corpus's. It re-runs each flow end to end:

  • it opens every report;
  • it checks each share's extensions and token as its aggregator would;
  • it recombines each measurement;
  • it runs both aggregators' verification;
  • it requires the uploads, the aggregation job, the hold and each collection to match byte for byte.

It also writes the catalogue, the files, the contribution, the plan, the settlement and the table itself. telemetry_aggregate_verify.py names measure 5, and stitched_presentation_verify.py can judge through step 10. Both of those corpora verify unchanged.

Across the parts

  • Breaking changes. Each entry file names the public API it breaks:
    • the new ClaimClass, ClaimBody and Reason variants of the two claim classes;
    • takedown::Case::cache_transmissions;
    • the telemetry_aggregate items the shared changes alter;
    • WireKind::DapReportExtension.
  • No behaviour changes. Four of the source commits make the files this branch changes clippy-clean: 64c735f0c, 91c5291cf, 8e479daff and 3c9f20524. Where boxing a field would change a public type, the lint is allowed where the type is declared, as the crate already does for items whose form is their API.
  • Feature gates. Source commit 987625394 builds Item::with_authority and Count::instance_received only under the feature that calls each, so a build with another feature no longer warns that they are unused.

How it was verified

This commit, 793ed1f2d.

  • Locally (git and Python checks only): scripts/wai-conformance-lists.py selftest and check, scripts/wai-conformance-lists-selftest.sh, scripts/check-changelog-fragment.py against main, scripts/changelog-assemble.py --check and scripts/changelog-fragments-selftest.sh all pass.
  • The layout changes only the layout. A comparison of trees shows that the change is the source branch's change except for the three differences listed above. The entry files hold exactly the lines the source branch added to wai/CHANGELOG.md. By #632's dry-run, the step files give the workflow the same features, paths, steps and commands that the source branch's workflow edits gave it. The registry change is the same rows, reordered. That comparison was made on the conversion's first base, #632's earlier tip 14f1abb7c; rebasing onto 946f3beda left every file's change the same.
  • On a Linux x86_64 build host: cargo check --locked --no-default-features --features <list> --tests in wai/wai-rs, for each of timeliness, rung_price, cache_authority, impression_aggregate, bearer_receipts, carousel, takedown, telemetry_aggregate, key_discovery, route_record, stitched_presentation, http,receipt_claims, and the four new features together with takedown and http. All pass.
  • With the other converted branches. This branch merges without conflict with each of the other branches converted to #632's layout (by git merge-tree). Merging all of them in forward, reverse and a mixed order gives one tree. On the build host, that tree passes these runs: cargo check --tests under the derived WAI_FEATURES and under WAI_PQ_FEATURES; cargo check --tests of quickstart,app; the catalogue's library tests; and the wai binary's unit tests.

The source branch, at 987625394, before conversion. This ran on a Linux x86_64 build host, on a snapshot of the branch, with the toolchain rust-toolchain.toml pins (Rust 1.99.1, clippy 0.1.99), Python 3.11 and CARGO_BUILD_JOBS=12.

  1. The conformance workflow as that tip had it, run step by step.
    • Independent-verifiers job: every step, except the cargo test lines of modules the branch does not change. Pass 3 below runs those of the modules that use one it changes, and the rest are left to CI.
    • Claim corpus: the verify and its pin tests.
    • Library unit tests: the cargo-classes job's command.
    • Features alone: every feature list in the loop, each on its own, plus wai-live-web. No list warns in a file the branch changes.
    • Clippy: wai-rs under the union of features with --all-targets, with no finding in a file the branch changes; the neural_int guard; and -D warnings for wai-key-proxy, wai-ledger, wai-audit, wai-fleet, wai-pack and wai-studio core.
    • Repository checks: check-tests-in-ci, check-spec-refs and check-wai-section-refs, with their self-tests; the workflow-concurrency and wasmtime-pin checks; check-no-vanity-metrics.sh; the public-text self-test, check-comparative-prose.sh and check-public-names.sh --maintainer-products-only.
    • Afterwards: git status was empty, so every corpus that a step regenerates came out identical.
  2. The other steps the branch's files reach: wai registry export --check; the carriage, manifest-builder, CLI and corpus-provenance tests; the signer-id and wai_keys_cli tests; key_log checked for wasm32 with key_discovery,http; the frozen-hash loop; and the HTTP corpus's differential and its shard list, as wai-http.yml runs them.
  3. A second, separate pass.
    • Generators: rebuilt under the union of features, each regenerated its corpus into a fresh copy that was diffed against the committed file: timeliness, prices, cache authority, impressions, takedown, telemetry aggregate, carousel, bearers, routes, holdings, settlement, stitched presentation, claim, signer and HTTP. None differs. The HTTP generator could not find a relative input when run outside the tree, so it was rerun inside the tree, and it matched.
    • Claim corpus: verified under the frozen-hash loop's feature list, with its pins.
    • Tests: the four modules' --test runs and those of every other module the branch changes; every library test under the union of features; the integration tests of the modules that use a module the branch changes; and the post-quantum signature tests.
    • Second implementations: the Python second implementations of the four new corpora and of the takedown, telemetry-aggregate, stitched-presentation, carousel, bearer, route-record, claim, signer and HTTP corpora, each over its corpus, and claim_verify.py in its timeliness and cache-authority modes.
    • Clippy, and features alone with warnings collected: no feature list warns in a file the branch changes. At 987625394's parent, the same lists warned that with_authority and instance_received were unused, and at 987625394 they do not.

Earlier, on an arm64 build host with the toolchain pinned then (Rust 1.98.0), each of the four part tips passed the independent-verifiers job's verifier steps with the --test and --lib runs of the parts' modules, clippy with no finding in a file the part changes, and the features-alone loop for every feature that exists at that tip. The library job's command also ran at the first and the last part tips.

On the CI hosts. Results on the CI runners come from this pull request's own CI run. None of the runs above is a CI result.

🤖 Generated with Claude Code

## What this is Four WAI extensions for one-way delivery: when an object is of use and whether it was held in time (timeliness), what delivering a rung costs (rung price), who served what a node holds and on whose authority (cache authority), and ad presentations counted with no return path (impression aggregates). They come in that order, the order they build on each other. **Merge order.** This branch sits on #632's commit, 946f3beda, which moves changelog entries into `wai/changes/` and the conformance workflow's lists into step files. Merge #632 first; until it merges, this pull request's diff also shows #632's change. The pull request of `wai/ad-consent-supply-chain` is stacked on this one. **What it carries.** One commit, 793ed1f2d: the change of `wai/one-way-delivery` (f1258784d..987625394) in #632's layout. Its message lists the source commits. Compared with the source branch: - its four changelog entries are four files of `wai/changes/`, each holding the text the source branch added to `wai/CHANGELOG.md`; - its edits to `wai-conformance.yml` are step files of `.github/wai-conformance/verifiers/`: `timeliness.sh`, `rung-price.sh`, `cache-authority.sh` and `impression-aggregates.sh`, each with its feature and the extension path it reads, and the takedown step's prose edit goes into `takedown.sh`; - in `codecs/registry.rs` the new rows sit beside the rows they build on instead of at the end: the rung-price wire rows above the route-record rows, `IMPRESSIONS` beside `TELEMETRY_AGGREGATION` and `RUNG_PRICE` just before `ROUTE_RECORD`. The rows are the same; only their place changed. Every other file is as the source branch has it. Each part gets the same supporting changes: - a registry row in `codecs/registry.rs`, with `REGISTRY.md`, `registry/capabilities.json` and `vocab/v2.ttl` regenerated by `wai registry export`; - a SPEC §5 paragraph and a changelog entry file; - a step file that runs the module's tests and its second implementation. Its `features:` line puts the feature into `WAI_FEATURES`, the `--test` list and the features-alone lists, and its `paths:` line puts the extension into the workflow's trigger, through #632's derivation. Each corpus is written from fixed seeds by its generator, and none is edited by hand. ## 1. Timeliness (`wai.delivery.timeliness`, `extensions/timeliness.md`) **What it defines.** This is a publisher's signed statement, for each object of a group, of when the object is of use. It states: - the instant the object is useful from; - the deadline by which a receiver must hold it for its full value; - how that value falls after the deadline, as a stated piecewise-linear function in parts per million that reaches 0 at its end; - the rendition a receiver presents in its place, which is a separate object derived from the primary. The statement is a jwp-receipts claim of class `timeliness` (§2.4.17), signed by the group's key beside the group receipt, one statement for every bearer. A verifier reads holdings records, which are a holder's signed word that it held an object at an instant. From them it judges each object for each holder as a sink deciding at the deadline would present it: on time, replaced by its fallback, held only after the deadline and at what value at least, or not shown. Every instant is an upper bound on arrival, so every value is a lower bound. An asker can also plan each object from an instant it states. It goes over its sources in its own order (a carousel's passes, a neighbour's holdings, the origin) and gets the first source that is on time, the fallback, or the best late source. The deadline is mapped onto parameters the bearers already define, and WAI defines no transport. delivery-telemetry gains the switch reason `not-held-by-deadline`. A layer of a stage set has no entry and is not a fallback, because staged-delivery alone decides whether a layer is late. **The reference.** The `timeliness` module of `wai-rs`, with the class's body in `claim_receipt::timeliness`. `wai_timeliness_vectors verify` and `tests/timeliness.rs` check that: - the corpus regenerates byte for byte; - `wai-rs` gives every case its stated outcome; - every reason and every verdict outcome occurs; - the extension's reason list is exactly the code's; - jwp-receipts lists the class's codes at their steps. **The independent verifier.** `live-conformance/timeliness_verify.py` is written from the extension alone and shares no code with `wai-rs`. It uses the JWP, claim, carousel and holdings corpora's second implementations for what those texts define. It writes the rest itself: the checks against the group, the value function, the judging and the planning. It reads the reason codes and outcomes from the text. It requires every mutated copy of the corpus to fail. It drops each of its own checks in turn and requires the corpus to catch each weakened verifier. It also checks the arithmetic at its extremes directly. **Beside it.** - `claim_verify.py` reads the new class. It also lists `not-held-by-deadline`. Before, the two claim verifiers disagreed about a session that switches for that reason, and the claim corpus now holds such a session. It is appended after every other vector, and a test pins the corpus before it. - `http_receipts.py` holds a timeliness claim in a receipt index to its group, as `wai-rs` does. Before, it accepted one without checking. ## 2. Rung price (`wai.delivery.rung_price`, `extensions/rung-price.md`) **What it defines.** This is a seller's signed list of what it charges to deliver a rung. Each price is for: - a direction; - a bearer class; - a footprint of region codes; - a ceiling on the rung's rate; - a unit, priced at the divisor of the ledger field that bills it. The energy the seller states sits beside each price. A seller's latest list stands alone, and a list that lapses brings back none of the earlier ones. §2 is WAI's one definition of a region code. It lives in the ungated `region` module, and other extensions cite it. A comparer's request removes the options its limits remove and ranks the rest by cost or by energy per receiver. A shared transmission's cost is divided by the audience the comparer states, or by one, and never by an assumed audience. The plan states the audience at which sharing costs no more, and the neighbour order an asker of holdings takes from it. A list is a quote: a buyer is billed only at a tariff it signed, and §7 says which tariff field bills each unit. **Energy ranked by checked evidence.** An earlier revision of this part ranked energy by the class a seller stated, and nothing tied the class to evidence. A seller that labelled its figure as calibrated outranked an honest model-based one, and the ranking ignored the declared uncertainty. Now: - an entry above the estimate class names, by digest, the seller's own per-hop records whose rate its figure is; - an entry of a hardware class states its uncertainty; - a comparer given those records holds them to five rules, in order: each record is a relay's, of the seller's own key, and of the entry's class; the entry declares their largest uncertainty; and the figure is their rate, rounded up; - the request states which (key, class) pairs the comparer has confirmed, and how old the evidence may be. Each candidate's evidence is then refuted, absent, outside its window, unconfirmed, or checked: - a refuted figure is set aside; - only a checked figure ranks at its class, and any other figure ranks as an estimate; - a key confirmed for another class confirms nothing; - a hardware figure is compared one declared uncertainty above itself; - a damaged copy of a record refutes nothing. A plan names the evidence it read. §10 states that a record's age is only its room's word. **The reference.** The `rung_price` module of `wai-rs`. `wai_rung_price_vectors verify` and `tests/rung_price.rs` check that: - the corpus regenerates byte for byte; - every case gets its outcome; - every reason occurs, and the extension lists exactly the code's; - every limit, decision, evidence verdict and energy rank occurs. Both implementations check the size bounds that no vector carries, and the evidence-text bound is tested on both sides of each of its edges. **The independent verifier.** `live-conformance/rung_price_verify.py` is written from the extension alone and shares no code with `wai-rs`. It reads: - documents with route-record's second implementation; - per-hop records with live-metering's; - room descriptors with fleet's; - signatures with the shared strict Ed25519 check. It writes the region code, the list rules, the verdicts and the comparison itself, and requires every mutated copy of the corpus to fail. Its weakened verifiers include the defect fixed above, a stated class deciding the rank, and also key-only confirmation, each uncertainty ordering and each edge of the evidence window. The corpus holds the attack on an honest model-based figure in each of its forms. ## 3. Cache authority (`wai.delivery.cache`, `extensions/cache-authority.md`) **What it defines.** A node's operator gives the caches and peers it runs two authorities in its key log: the role `cache/serve` and the class authority `cache-transmission`. Under the role, a key signs its holdings records and its declarations, and it is the upstream its receivers acknowledge. Neither authority lets the key author, transform or sign a publisher's statement. A relying party places a server key by the key-log heads it names, in jwp-receipts' three levels: - a revoked key is refused; - a retired key past its `until` is refused; - a head that lists the key with no serving role refuses it; - a key that no head lists is unconfirmed; - a head that cannot be read confirms nothing. A placement labels a server and never changes a verdict. The `cache-transmission` claim (jwp-receipts §2.4.18) is a node's declaration that it sent, from what it held, objects of a group another key signed, over a multicast or unidirectional instance of its own. The claim carries a bitmap and a root under the publisher's tree, which are checked without the bytes. It is refused when the group's own key signs it, or when the instance is two-way. The bearer verdict credits a cache per instance, only for what it says it sent, and a cache's instance never makes a group `transmitted`. **Held by a deadline.** A relying party states a population of receiver keys for a region. The count is how many of those keys held an object by a deadline, on their own signed word: acknowledgements, counted reconciliations, or holdings records. The miss rate is in parts per million, rounded up, and every unknown is a miss. §9 derives timeliness lines from all three kinds of statement. Timeliness' own verdict still reads holdings records alone. **The reference.** The `cache_authority` module of `wai-rs`, with the class's body in `claim_receipt::bearer`. `wai_cache_authority_vectors verify` and `tests/cache_authority.rs` check that: - the corpus regenerates byte for byte; - every case gets its outcome; - every reason occurs, and the extension lists exactly the code's. **The independent verifier.** `live-conformance/cache_authority_verify.py` is written from the extension alone and shares no code with `wai-rs`. It uses the JWP, claim, bearer, settlement, signer, timeliness and rung price corpora's second implementations for what those texts define. It writes the placement, the claim's checks against its group, the verdict and the count itself. It requires every mutated copy of the corpus to fail and the corpus to catch each weakened verifier, and it checks the population bound directly. `claim_verify.py cache-authority` reads every claim through steps 1 to 4. **Beside it.** - Takedown reads a cache-transmission claim as its signer's word that it held what it sent. `takedown_verify.py` now does too. Before, it failed the committed takedown cases that carry such a claim. - Settlement places a serving node by `cache/serve`. - The receipt-index check of http-delivery holds a cache-transmission claim to its group in both implementations. Before, the second implementation accepted one without checking. ## 4. Impression aggregates (`wai.delivery.impressions`, `extensions/impression-aggregates.md`) **What it defines.** This part counts ad presentations over a bearer with no return path, as measure 5, `impressions`, of telemetry-aggregation. A receiver judges each shared stitched ad it presented by stitched-presentation's rules. It turns each presentation into one Prio3Histogram report of creative × region × quartile. It defines three formats: - a catalogue (`WIC1`), which fixes which index is which, bound as the task's scope; - a task file (`WIT1`), whose signer the receiver confirms under its pinned key log with the new pinned-only authority `aggregate/task`, so a task key can be revoked over the bearer; - an upload file (`WIU1`), which relays forward unchanged. One-way delivery shapes the rest: - a report is generated once, stored and re-sent until it is settled, and never regenerated; - a duplicate is discarded by its id; - the leader holds each collection for the catalogue's hold, and the aggregators keep the task until its retention instant, so late reports still count; - a report later than that is lost, so a count can be lower than what was presented, never higher; - with attestation, each report carries a token bound to its task and its report id. A reader verifies a receipt against its catalogue and recomputes a table of presentations and quartile counts per creative and region. The table is a lower bound on reported presentations. It is never an audience, and never billed as presented. Its totals are exact, and a receipt given twice counts as checked when either copy was. The shared changes to `telemetry_aggregate` keep every corpus they touch byte for byte. **The reference.** The `impression_aggregate` module of `wai-rs`. `wai_impression_aggregate_vectors verify` and `tests/impression_aggregate.rs` check that: - the corpus regenerates byte for byte; - every case gets its outcome; - every reason occurs, and the extension lists exactly the code's; - each standing receipt's result is the plaintext tally of the contributions its reports came from; - stitched-presentation's own verification gives the same per-creative counts. The file size bounds are tested at exactly the bound and at one byte over it. **The independent verifier.** `live-conformance/impression_aggregate_verify.py` is written from the extension alone and shares no code with `wai-rs`. It evaluates Prio3 and opens reports with the QoE corpus's second implementation. It judges claims with stitched-presentation's, verifies tokens with ad-presentation's, and confirms task-file signers with the signer corpus's. It re-runs each flow end to end: - it opens every report; - it checks each share's extensions and token as its aggregator would; - it recombines each measurement; - it runs both aggregators' verification; - it requires the uploads, the aggregation job, the hold and each collection to match byte for byte. It also writes the catalogue, the files, the contribution, the plan, the settlement and the table itself. `telemetry_aggregate_verify.py` names measure 5, and `stitched_presentation_verify.py` can judge through step 10. Both of those corpora verify unchanged. ## Across the parts - **Breaking changes.** Each entry file names the public API it breaks: - the new `ClaimClass`, `ClaimBody` and `Reason` variants of the two claim classes; - `takedown::Case::cache_transmissions`; - the `telemetry_aggregate` items the shared changes alter; - `WireKind::DapReportExtension`. - **No behaviour changes.** Four of the source commits make the files this branch changes clippy-clean: 64c735f0c, 91c5291cf, 8e479daff and 3c9f20524. Where boxing a field would change a public type, the lint is allowed where the type is declared, as the crate already does for items whose form is their API. - **Feature gates.** Source commit 987625394 builds `Item::with_authority` and `Count::instance_received` only under the feature that calls each, so a build with another feature no longer warns that they are unused. ## How it was verified **This commit, 793ed1f2d.** - **Locally** (git and Python checks only): `scripts/wai-conformance-lists.py selftest` and `check`, `scripts/wai-conformance-lists-selftest.sh`, `scripts/check-changelog-fragment.py` against main, `scripts/changelog-assemble.py --check` and `scripts/changelog-fragments-selftest.sh` all pass. - **The layout changes only the layout.** A comparison of trees shows that the change is the source branch's change except for the three differences listed above. The entry files hold exactly the lines the source branch added to `wai/CHANGELOG.md`. By #632's `dry-run`, the step files give the workflow the same features, paths, steps and commands that the source branch's workflow edits gave it. The registry change is the same rows, reordered. That comparison was made on the conversion's first base, #632's earlier tip 14f1abb7c; rebasing onto 946f3beda left every file's change the same. - **On a Linux x86_64 build host:** `cargo check --locked --no-default-features --features <list> --tests` in `wai/wai-rs`, for each of `timeliness`, `rung_price`, `cache_authority`, `impression_aggregate`, `bearer_receipts`, `carousel`, `takedown`, `telemetry_aggregate`, `key_discovery`, `route_record`, `stitched_presentation`, `http,receipt_claims`, and the four new features together with `takedown` and `http`. All pass. - **With the other converted branches.** This branch merges without conflict with each of the other branches converted to #632's layout (by `git merge-tree`). Merging all of them in forward, reverse and a mixed order gives one tree. On the build host, that tree passes these runs: `cargo check --tests` under the derived `WAI_FEATURES` and under `WAI_PQ_FEATURES`; `cargo check --tests` of `quickstart,app`; the catalogue's library tests; and the `wai` binary's unit tests. **The source branch, at 987625394, before conversion.** This ran on a Linux x86_64 build host, on a snapshot of the branch, with the toolchain `rust-toolchain.toml` pins (Rust 1.99.1, clippy 0.1.99), Python 3.11 and `CARGO_BUILD_JOBS=12`. 1. **The conformance workflow as that tip had it, run step by step.** - **Independent-verifiers job:** every step, except the `cargo test` lines of modules the branch does not change. Pass 3 below runs those of the modules that use one it changes, and the rest are left to CI. - **Claim corpus:** the verify and its pin tests. - **Library unit tests:** the cargo-classes job's command. - **Features alone:** every feature list in the loop, each on its own, plus `wai-live-web`. No list warns in a file the branch changes. - **Clippy:** `wai-rs` under the union of features with `--all-targets`, with no finding in a file the branch changes; the `neural_int` guard; and `-D warnings` for `wai-key-proxy`, `wai-ledger`, `wai-audit`, `wai-fleet`, `wai-pack` and `wai-studio` core. - **Repository checks:** `check-tests-in-ci`, `check-spec-refs` and `check-wai-section-refs`, with their self-tests; the workflow-concurrency and wasmtime-pin checks; `check-no-vanity-metrics.sh`; the public-text self-test, `check-comparative-prose.sh` and `check-public-names.sh --maintainer-products-only`. - **Afterwards:** `git status` was empty, so every corpus that a step regenerates came out identical. 2. **The other steps the branch's files reach:** `wai registry export --check`; the carriage, manifest-builder, CLI and corpus-provenance tests; the signer-id and `wai_keys_cli` tests; `key_log` checked for wasm32 with `key_discovery,http`; the frozen-hash loop; and the HTTP corpus's differential and its shard list, as `wai-http.yml` runs them. 3. **A second, separate pass.** - **Generators:** rebuilt under the union of features, each regenerated its corpus into a fresh copy that was diffed against the committed file: timeliness, prices, cache authority, impressions, takedown, telemetry aggregate, carousel, bearers, routes, holdings, settlement, stitched presentation, claim, signer and HTTP. None differs. The HTTP generator could not find a relative input when run outside the tree, so it was rerun inside the tree, and it matched. - **Claim corpus:** verified under the frozen-hash loop's feature list, with its pins. - **Tests:** the four modules' `--test` runs and those of every other module the branch changes; every library test under the union of features; the integration tests of the modules that use a module the branch changes; and the post-quantum signature tests. - **Second implementations:** the Python second implementations of the four new corpora and of the takedown, telemetry-aggregate, stitched-presentation, carousel, bearer, route-record, claim, signer and HTTP corpora, each over its corpus, and `claim_verify.py` in its timeliness and cache-authority modes. - **Clippy, and features alone with warnings collected:** no feature list warns in a file the branch changes. At 987625394's parent, the same lists warned that `with_authority` and `instance_received` were unused, and at 987625394 they do not. Earlier, on an arm64 build host with the toolchain pinned then (Rust 1.98.0), each of the four part tips passed the independent-verifiers job's verifier steps with the `--test` and `--lib` runs of the parts' modules, clippy with no finding in a file the part changes, and the features-alone loop for every feature that exists at that tip. The library job's command also ran at the first and the last part tips. **On the CI hosts.** Results on the CI runners come from this pull request's own CI run. None of the runs above is a CI result. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wai/one-way-delivery, converted to the layout of the fix: no shared append point
All checks were successful
WAI examples / WAI examples · portable · linux (pull_request) Successful in 24m50s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 18m38s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m31s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 7m3s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m46s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 8m4s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m47s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 17m16s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (pull_request) Successful in 7m47s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 34m23s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 21s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 16s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 7m5s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 18s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 37m20s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 10m52s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 18m17s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 11m18s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 39m59s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 15s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 40m12s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 50s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 2m42s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 3m47s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 17m30s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 18m34s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 14m28s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 14m15s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 30m4s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h18m5s
793ed1f2dc
The change of wai/one-way-delivery (f1258784d..987625394, 28 commits), on the fix branch: its
changelog entries as files of wai/changes/, its wai-conformance.yml edits as step files,
corpus files and test tags, and every other file as the branch has it.

- 25240c4f0 wai: timeliness — when each object of a group is of use, and whether each holder held it in time
- c84992362 wai: timeliness_verify.py — the timeliness corpus's second implementation
- 44036fcdc wai: timeliness in the registry, SPEC §5, the changelog and CI; http_receipts.py checks its claims
- 27ce6754c wai: claim_verify.py lists not-held-by-deadline, and the claim corpus holds a session that switches for it
- 73d8d8eb9 wai: timeliness corpus — each holder's own line in key order, a holder's earliest fallback, and §7.2–§7.3's unreached plan rules
- 64c735f0c wai: the files timeliness changes are clippy-clean — a let chain, and the fetch callback's type allowed
- b72dc36bf wai: rung price — what delivering a rung costs, by bearer and direction, and which option a comparer takes
- 4e905e213 wai: rung_price_verify.py — the rung price corpus's second implementation
- 711fa6126 wai: rung price in the registry, SPEC §5, the changelog and CI
- 8ab70654e wai: rung price corpus — a refusal for every form rule 1 and §6.1 set, and the neighbour order a plan gives
- 1bc465959 wai: rung price ranks energy by checked evidence — a class counts only on the seller's own per-hop records, current and under a confirmed key
- 9e97997d9 wai: rung_price — the evidence text bound at its exact sizes, and a key confirmed for another class confirming nothing
- 8f1168683 wai: rung price corpus — a key confirmed for another class, the uncertainty product, each edge and order of the evidence verdict, and the evidence a plan read
- 7330e26ff wai: rung price — §6.1 links jwp-receipts at its first mention, and §10 says a record's age is its room's word
- 12c099457 wai: cache authority — who served what a node holds, and on whose authority
- f8f5d3e09 wai: cache_authority_verify.py — the cache authority corpus's second implementation
- 354146619 wai: cache authority in the registry, SPEC §5, the changelog and CI; its corpus holds what §12 states
- 55c7f3031 wai: timeliness §6 reads holdings records alone; cache-authority §9 derives the lines that read every kind
- b8fc6f02b wai: cache authority's lines read records as timeliness does, its deadline claim meets the envelopes held, and its corpus fixes each order and instant
- 91c5291cf wai: the files cache authority changes are clippy-clean — a boxed envelope, the base's names named once, slices borrowed
- 8e479daff wai: a held envelope boxes both its forms, so neither outweighs the other
- 3ec8da807 wai: impression aggregates — ad presentations counted over a bearer with no return path
- 0433a35c3 wai: impression_aggregate_verify.py — the impression aggregates corpus's second implementation
- 7d8e150e4 wai: impression aggregates in the registry, SPEC §5, the changelog and CI; its corpus states each receipt whole and a control for every malformed file
- d5e8ace02 wai: impression aggregates' size bounds are checked at their edge, and §4.3's decides no outcome
- 4bc8e13bd wai: impression aggregates' table totals are exact, and a receipt given twice is checked when either occurrence was
- 3c9f20524 wai: key_log's two result enums keep their public form, and say so to clippy
- 987625394 wai: Item::with_authority and Count::instance_received build only with the feature that calls each

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!633
No description provided.