wai: proof that an ad was presented — a player-signed presentation claim, and a spend that counts only presented impressions (E7) #398

Merged
dcharlot merged 9 commits from wai/ad-presentation into main 2026-10-21 22:28:49 -04:00
Owner

E7: proof that an ad was presented

live-ads §12 said quartiles_reached "is the decider's statement of the beacons it received; a receipt binds it and its billing, not the beacons". This PR adds a player-signed presentation claim for each impression and an ad-policy option under which a receipt's spend counts only impressions whose claim verifies.

What is in it

  • wai/extensions/ad-presentation.md registers the record wai.live.ad_presentation.
    • The claim, WPC1 (§5). It names the impression by the break digest, the session and the slot of its form-2 wai.video.ssai receipt. It carries:
      • the creative digest and the content hashes of the creative's objects the player presented;
      • the spans of media time, each with the least fraction of pixels observed in view (in basis points) and whether it was audible;
      • the geometry measured over: the ad's pixels, the player's area, or a TV full screen;
      • a rendered-frame count where the platform exposes one;
      • an optional device-attestation token.
    • The session key (§3). The claim is signed by a per-session Ed25519 key, and the receipt's session is derived from that key and the room. The decider never chooses the session, and it links nothing across rooms.
    • The creative digest (§4). It is computed over the creative's object hashes and durations. The pod, the receipt and the asset-list URIs name a creative by it.
    • Viewability (§6). Both rules are cited with their exact wording:
      • video: at least 50% of the ad's pixels for 2 continuous seconds (Viewable Ad Impression Measurement Guidelines (Desktop) v2.0, "Requirements for Viewable Video Advertising Impressions", p. 8);
      • cross-media: 100% of the pixels for 2 continuous seconds. On a TV this "may be assumed … without direct measurement" (Cross-Media Audience Measurement Standards (Phase I Video) §2.2.1).
      • The quartile is the contiguous coverage from the start, measured at VAST 4.3 §3.14.1's marks, and must equal the receipt's quartiles_reached.
    • Attestation (§7). The token is an RFC 9577 §2.2.1 token. Its TokenChallenge's redemption_context is a digest of this impression and this session key, so one token answers one impression. Type 0x0002 is verified with the issuer's key as RFC 9578 §6.4 specifies; type 0x0001 can only be verified by its issuer.
    • Policy fields (§8). WAP1 version 2 adds presentation (claim / attest / audible), viewability, token_type and issuer.
    • Verdicts (§9). Each claim gets a verdict, and each impression is counted or not.
    • The player (§10). What a player must measure (polling of at least 200 ms) and how.
    • Security considerations (§13) state plainly what a claim cannot prove without attestation, and what attestation bounds and what it does not.
  • live-ads.md: policy version 2; the session derived from the session key; §9.3 step 12 counts the presented spend under a policy that requires claims. Version-1 policies and every existing receipt verify as before, and live-conformance/ads/ is byte-for-byte unchanged.
  • wai-rs (feature live_ads, which now takes num-bigint, already an optional dependency for oer):
    • src/live_ads/presentation.rs: the claim, its rules and signature, quartile, run, attestation, DER SPKI and RSASSA-PSS, and the ledger;
    • live_ads.rs: policy v2 and the billing rule in verify;
    • presentation_corpus.rs, the bin wai_ad_presentation_vectors, and tests/ad_presentation.rs.
  • Corpus wai/live-conformance/presentation/: 5 rooms. The issuer key and the first test vector are from RFC 9578 Appendix A.2, and that vector is verified first.
    • Good impressions: video rule (fully in view; partly in view with a 3 s run at 60%; measured over the player's area) and attested TV impressions under the cross-media rule.
    • Negative controls, each with its reason:
      • claim_not_viewable: 40% of pixels; two 1.5 s runs separated by a pause; a TV assumption under the video rule; muted when audibility is required; 90% under the cross-media rule;
      • claim_duplicate;
      • claim_key_unbound: signed by another session's key;
      • claim_asset_mismatch;
      • claim_quartile_mismatch;
      • bad_signature, after which the impression is claim_absent;
      • claim_malformed: a signed claim that skips without a resumption flag, and a truncated claim;
      • claim_no_decision;
      • attestation_absent;
      • attestation_invalid: another impression's token, and an altered authenticator;
      • ad_policy_malformed.
    • Spend-equivalence: two receipts that would breach the ceiling if both were billed are accepted when only one is presented, and refused with funds_exceeded when both are.
  • ad_presentation_verify.py: an independent verifier written from the text (standard library only, run with -I). It verifies rooms, policies and receipts through live_ads_verify.py, which now reads policy v2 and takes a claims judge. It judges every claim itself and implements RSASSA-PSS and DER parsing itself.
  • Reference producer in the browser client: joule-moq-web/web/ads/presentation.js.
    • A span recorder fed by IntersectionObserver, page visibility and focus, volume and mute, current time and playback-quality frames.
    • It writes and signs the claim with WebCrypto Ed25519.
    • presentation.test.mjs turns observation sequences into three of the corpus's claims, byte for byte, and checks the attestation challenge against the corpus's token.
    • No page plays ads yet.
  • CI: a new step "ad presentation" in wai-conformance.yml, with setup-node 22 and paths for the extension and web/ads. joule-moq-web/e2e/run.sh runs the producer test with the page's other unit tests, and joule-moq-web.yml adds the corpus path.
  • Docs and registry: REGISTRY.md (record and WPC1), the registry export, a SPEC §5 paragraph, and the CHANGELOG.

Design decisions

  • A binary record in live-ads style, not a JWP claim class. It is verified inside the ads verifier, next to the receipt it bills. No jwp-receipts class number is taken.
  • The session is derived from the player's key. This binds the key to the session without changing the form-2 receipt's signed bytes. It also stops the decider choosing which key a session has, although a decider can still make up its own key; §13 says so.
  • Claim verdicts never refuse a room. A stripped or failed claim is simply not counted, and only live-ads' own refusals (funds_exceeded on the presented spend among them) refuse a room.
  • The impression's own claim is the first one in list order that is well formed, validly signed and bound to the session's key. An attacker without the key cannot block it by submitting a bad claim first.
  • The receipt's quartile must equal the claim's quartile, so buyer and seller reconcile one figure.
  • RSASSA-PSS uses a 48-byte salt, as RFC 9578 §6.4 states. §8.2.2 also lists a PSSZERO variant; this revision does not verify it, and says so.
  • The policy can choose the player's area as the geometry (geometry 3). This carries the disclosure the 2015 guidelines' footnote asks for.
  • No standalone CTV viewability rule exists in the texts read. The 2021 SSAI/OTT guidance §2 applies the digital video rules to CTV, so the room authority picks the video or cross-media rule.

Standards read at source

text read
Viewable Ad Impression Measurement Guidelines (Desktop) v2.0, 18 Aug 2015 (video text identical in v1.0, 30 Jun 2014) in full
Mobile Viewable Ad Impression Measurement Guidelines, 28 Jun 2016 video section only
Cross-Media Audience Measurement Standards (Phase I Video), Sep 2019 exec summary, §2.1.1, §2.1.5, §2.2.1, §2.3.1, §4.1.1 only
Server-Side Ad Insertion and OTT Guidance, Aug 2021 in full
Digital Video Impression Measurement Guidelines v1.1, Jun 2018 §3.0, §4.1, §4.4, §4.5
VAST 4.3, Dec 2022 §§1.1–1.2.1, 2.3.4, 2.4–2.4.3, 3.4.4, 3.5–3.5.3, 3.14–3.14.2, 3.16–3.17.5, 6; rest not read
SIMID 1.2 §§1–3.5.1, 4.2.10–11, 4.4.5, 4.4.7, 8.1, 8.4
OMID API v1.5, Jun 2024 impression, media, volumeChange, playerStateChange, geometryChange, AdView, reasons
Open Measurement Device Attestation Implementation Guidance v1.0, Nov 2025 in full
RFC 9576, RFC 9577, RFC 9578 in full; RFC 9474 §5

Not read, or not found:

  • Native OM SDKs: not read.
  • Player-to-verifier exchange: no public text describes the exchange between a player and an attestation verifier's URL.
  • Token type used by OM device attestation: the guidance does not say which Privacy Pass token type it uses (§4.2.2 says to support both).
  • RFC 8017: not re-read. Its RSASSA-PSS is implemented as RFC 9578 §6.4 cites it, and checked against RFC 9578's own test vector, both in Rust and in Python.

Checks

check command result
live_ads lib tests rb … cargo test --locked --no-default-features --features live_ads --lib 648 passed
corpus tests rb … cargo test --locked --no-default-features --features live_ads --test ad_presentation --test live_ads 3 + 3 passed
corpus regenerates rb … wai_ad_presentation_vectors verify ../live-conformance/presentation, wai_live_ads_vectors verify ../live-conformance/ads PASS, PASS (ads corpus unchanged)
registry tests rb … cargo test --locked --lib codecs::registry 14 passed
registry export rb --pull … wai -- registry export, then registry export --check up to date
clippy rb … cargo clippy --locked --no-default-features --features live_ads --all-targets no notes in touched files (one useless_vec found and fixed)
Cargo.lock rb … cargo metadata --locked --offline --format-version 1 ok, no lock change
independent verifier python3 -I live-conformance/ad_presentation_verify.py live-conformance/presentation PASS: 5 rooms, every reason, 17 mutated copies fail, 10 dropped checks caught
every live verifier each live-conformance/*_verify.py on its corpus, after merging main all exit 0
reference producer node --test web/ads/presentation.test.mjs 5 pass
repo checks check-tests-in-ci, check-workflow-concurrency, check-spec-refs, check-wai-section-refs, check-no-vanity-metrics, test-public-text-checks, check-comparative-prose, check-orphan-sources all exit 0
public names check-public-names.sh on every touched file and the commit messages clean

Falsifications (committed state; each mutation alone, then restored)

Rust, on the build host: with each of these mutations, cargo test --test ad_presentation fails with exit 101:

  • no session binding;
  • no duplicate rule;
  • no touched-objects check;
  • no quartile check;
  • a 1 s run accepted as viewable;
  • no challenge binding;
  • a 32-byte PSS salt in verification;
  • the billable spend counted instead of the presented spend under a claim policy (live-ads step 12);
  • no resumption rule;
  • policy-v2 rules not checked.

Python: the verifier mutates copies of the corpus itself, and each mutated copy fails. It also drops each of its own checks in turn (rules, signature, session, duplicate, asset, quartile, viewability, attestation absent, challenge, authenticator), and the corpus catches every weakened verifier. When the "rules" check was first dropped, the corpus did not catch it; I added a signed claim that breaks a span rule.

JS: with each of these mutations, node --test exits 1:

  • the session domain changed;
  • a pause not marked as a resumption;
  • a span's last visible fraction stated instead of the lowest;
  • 16-bit lengths written big-endian;
  • the challenge written without origin_info.

Not done

  • The producer is not wired into a page: the room page plays no ads, and there is no browser end-to-end test of attach() with a real IntersectionObserver.
  • IntersectionObserver does not see what other elements cover the player; §10 says so.
  • Tokens of type 0x0001 cannot be verified by the reference, since only the issuer can verify them.
  • No issuance flow: no claim from a real device. The corpus tokens are signed with the RFC's published test key.
  • Invalid-traffic classes are not modelled.
  • §13 states that a vouched device running modified software still signs whatever it is told to.

Existing issue on main (not in this PR)

WAI_NAME_DENYLIST=… scripts/check-public-names.sh over all of wai/ reports hits in wai/wai-rs/src/live_provenance.rs (lines 381–402, 648, 657, 1780–1781), which came from #381. That file is untouched here.

🤖 Generated with Claude Code

## E7: proof that an ad was presented live-ads §12 said `quartiles_reached` "is the decider's statement of the beacons it received; a receipt binds it and its billing, not the beacons". This PR adds a player-signed **presentation claim** for each impression and an ad-policy option under which a receipt's spend counts only impressions whose claim verifies. ### What is in it - **`wai/extensions/ad-presentation.md`** registers the record `wai.live.ad_presentation`. - **The claim, `WPC1` (§5).** It names the impression by the break digest, the session and the slot of its form-2 `wai.video.ssai` receipt. It carries: - the creative digest and the content hashes of the creative's objects the player presented; - the spans of media time, each with the least fraction of pixels observed in view (in basis points) and whether it was audible; - the geometry measured over: the ad's pixels, the player's area, or a TV full screen; - a rendered-frame count where the platform exposes one; - an optional device-attestation token. - **The session key (§3).** The claim is signed by a per-session Ed25519 key, and the receipt's session is derived from that key and the room. The decider never chooses the session, and it links nothing across rooms. - **The creative digest (§4).** It is computed over the creative's object hashes and durations. The pod, the receipt and the asset-list URIs name a creative by it. - **Viewability (§6).** Both rules are cited with their exact wording: - **video:** at least 50% of the ad's pixels for 2 continuous seconds (*Viewable Ad Impression Measurement Guidelines (Desktop)* v2.0, "Requirements for Viewable Video Advertising Impressions", p. 8); - **cross-media:** 100% of the pixels for 2 continuous seconds. On a TV this "may be assumed … without direct measurement" (*Cross-Media Audience Measurement Standards (Phase I Video)* §2.2.1). - The quartile is the contiguous coverage from the start, measured at VAST 4.3 §3.14.1's marks, and must equal the receipt's `quartiles_reached`. - **Attestation (§7).** The token is an RFC 9577 §2.2.1 token. Its TokenChallenge's `redemption_context` is a digest of this impression and this session key, so one token answers one impression. Type 0x0002 is verified with the issuer's key as RFC 9578 §6.4 specifies; type 0x0001 can only be verified by its issuer. - **Policy fields (§8).** `WAP1` version 2 adds `presentation` (claim / attest / audible), `viewability`, `token_type` and `issuer`. - **Verdicts (§9).** Each claim gets a verdict, and each impression is counted or not. - **The player (§10).** What a player must measure (polling of at least 200 ms) and how. - **Security considerations (§13)** state plainly what a claim cannot prove without attestation, and what attestation bounds and what it does not. - **`live-ads.md`**: policy version 2; the session derived from the session key; §9.3 step 12 counts the **presented spend** under a policy that requires claims. Version-1 policies and every existing receipt verify as before, and `live-conformance/ads/` is byte-for-byte unchanged. - **wai-rs** (feature `live_ads`, which now takes `num-bigint`, already an optional dependency for `oer`): - `src/live_ads/presentation.rs`: the claim, its rules and signature, quartile, run, attestation, DER SPKI and RSASSA-PSS, and the ledger; - `live_ads.rs`: policy v2 and the billing rule in `verify`; - `presentation_corpus.rs`, the bin `wai_ad_presentation_vectors`, and `tests/ad_presentation.rs`. - **Corpus `wai/live-conformance/presentation/`**: 5 rooms. The issuer key and the first test vector are from RFC 9578 Appendix A.2, and that vector is verified first. - **Good impressions:** video rule (fully in view; partly in view with a 3 s run at 60%; measured over the player's area) and attested TV impressions under the cross-media rule. - **Negative controls, each with its reason:** - `claim_not_viewable`: 40% of pixels; two 1.5 s runs separated by a pause; a TV assumption under the video rule; muted when audibility is required; 90% under the cross-media rule; - `claim_duplicate`; - `claim_key_unbound`: signed by another session's key; - `claim_asset_mismatch`; - `claim_quartile_mismatch`; - `bad_signature`, after which the impression is `claim_absent`; - `claim_malformed`: a signed claim that skips without a resumption flag, and a truncated claim; - `claim_no_decision`; - `attestation_absent`; - `attestation_invalid`: another impression's token, and an altered authenticator; - `ad_policy_malformed`. - **Spend-equivalence:** two receipts that would breach the ceiling if both were billed are accepted when only one is presented, and refused with `funds_exceeded` when both are. - **`ad_presentation_verify.py`**: an independent verifier written from the text (standard library only, run with `-I`). It verifies rooms, policies and receipts through `live_ads_verify.py`, which now reads policy v2 and takes a claims judge. It judges every claim itself and implements RSASSA-PSS and DER parsing itself. - **Reference producer in the browser client**: `joule-moq-web/web/ads/presentation.js`. - A span recorder fed by `IntersectionObserver`, page visibility and focus, volume and mute, current time and playback-quality frames. - It writes and signs the claim with WebCrypto Ed25519. - `presentation.test.mjs` turns observation sequences into three of the corpus's claims, byte for byte, and checks the attestation challenge against the corpus's token. - No page plays ads yet. - **CI**: a new step "ad presentation" in `wai-conformance.yml`, with `setup-node` 22 and paths for the extension and `web/ads`. `joule-moq-web/e2e/run.sh` runs the producer test with the page's other unit tests, and `joule-moq-web.yml` adds the corpus path. - **Docs and registry**: `REGISTRY.md` (record and `WPC1`), the registry export, a SPEC §5 paragraph, and the CHANGELOG. ### Design decisions - **A binary record in live-ads style, not a JWP claim class.** It is verified inside the ads verifier, next to the receipt it bills. No jwp-receipts class number is taken. - **The session is derived from the player's key.** This binds the key to the session without changing the form-2 receipt's signed bytes. It also stops the decider choosing which key a session has, although a decider can still make up its own key; §13 says so. - **Claim verdicts never refuse a room.** A stripped or failed claim is simply not counted, and only live-ads' own refusals (`funds_exceeded` on the presented spend among them) refuse a room. - **The impression's own claim is the first one in list order that is well formed, validly signed and bound to the session's key.** An attacker without the key cannot block it by submitting a bad claim first. - **The receipt's quartile must equal the claim's quartile**, so buyer and seller reconcile one figure. - **RSASSA-PSS uses a 48-byte salt**, as RFC 9578 §6.4 states. §8.2.2 also lists a PSSZERO variant; this revision does not verify it, and says so. - **The policy can choose the player's area as the geometry (geometry 3).** This carries the disclosure the 2015 guidelines' footnote asks for. - **No standalone CTV viewability rule exists in the texts read.** The 2021 SSAI/OTT guidance §2 applies the digital video rules to CTV, so the room authority picks the video or cross-media rule. ### Standards read at source | text | read | |---|---| | Viewable Ad Impression Measurement Guidelines (Desktop) v2.0, 18 Aug 2015 (video text identical in v1.0, 30 Jun 2014) | in full | | Mobile Viewable Ad Impression Measurement Guidelines, 28 Jun 2016 | video section only | | Cross-Media Audience Measurement Standards (Phase I Video), Sep 2019 | exec summary, §2.1.1, §2.1.5, §2.2.1, §2.3.1, §4.1.1 only | | Server-Side Ad Insertion and OTT Guidance, Aug 2021 | in full | | Digital Video Impression Measurement Guidelines v1.1, Jun 2018 | §3.0, §4.1, §4.4, §4.5 | | VAST 4.3, Dec 2022 | §§1.1–1.2.1, 2.3.4, 2.4–2.4.3, 3.4.4, 3.5–3.5.3, 3.14–3.14.2, 3.16–3.17.5, 6; rest not read | | SIMID 1.2 | §§1–3.5.1, 4.2.10–11, 4.4.5, 4.4.7, 8.1, 8.4 | | OMID API v1.5, Jun 2024 | impression, media, volumeChange, playerStateChange, geometryChange, AdView, reasons | | Open Measurement Device Attestation Implementation Guidance v1.0, Nov 2025 | in full | | RFC 9576, RFC 9577, RFC 9578 | in full; RFC 9474 §5 | **Not read, or not found:** - **Native OM SDKs:** not read. - **Player-to-verifier exchange:** no public text describes the exchange between a player and an attestation verifier's URL. - **Token type used by OM device attestation:** the guidance does not say which Privacy Pass token type it uses (§4.2.2 says to support both). - **RFC 8017:** not re-read. Its RSASSA-PSS is implemented as RFC 9578 §6.4 cites it, and checked against RFC 9578's own test vector, both in Rust and in Python. ### Checks | check | command | result | |---|---|---| | live_ads lib tests | `rb … cargo test --locked --no-default-features --features live_ads --lib` | 648 passed | | corpus tests | `rb … cargo test --locked --no-default-features --features live_ads --test ad_presentation --test live_ads` | 3 + 3 passed | | corpus regenerates | `rb … wai_ad_presentation_vectors verify ../live-conformance/presentation`, `wai_live_ads_vectors verify ../live-conformance/ads` | PASS, PASS (ads corpus unchanged) | | registry tests | `rb … cargo test --locked --lib codecs::registry` | 14 passed | | registry export | `rb --pull … wai -- registry export`, then `registry export --check` | up to date | | clippy | `rb … cargo clippy --locked --no-default-features --features live_ads --all-targets` | no notes in touched files (one `useless_vec` found and fixed) | | Cargo.lock | `rb … cargo metadata --locked --offline --format-version 1` | ok, no lock change | | independent verifier | `python3 -I live-conformance/ad_presentation_verify.py live-conformance/presentation` | PASS: 5 rooms, every reason, 17 mutated copies fail, 10 dropped checks caught | | every live verifier | each `live-conformance/*_verify.py` on its corpus, after merging main | all exit 0 | | reference producer | `node --test web/ads/presentation.test.mjs` | 5 pass | | repo checks | check-tests-in-ci, check-workflow-concurrency, check-spec-refs, check-wai-section-refs, check-no-vanity-metrics, test-public-text-checks, check-comparative-prose, check-orphan-sources | all exit 0 | | public names | `check-public-names.sh` on every touched file and the commit messages | clean | ### Falsifications (committed state; each mutation alone, then restored) **Rust, on the build host:** with each of these mutations, `cargo test --test ad_presentation` fails with exit 101: - no session binding; - no duplicate rule; - no touched-objects check; - no quartile check; - a 1 s run accepted as viewable; - no challenge binding; - a 32-byte PSS salt in verification; - the billable spend counted instead of the presented spend under a claim policy (live-ads step 12); - no resumption rule; - policy-v2 rules not checked. **Python:** the verifier mutates copies of the corpus itself, and each mutated copy fails. It also drops each of its own checks in turn (rules, signature, session, duplicate, asset, quartile, viewability, attestation absent, challenge, authenticator), and the corpus catches every weakened verifier. When the "rules" check was first dropped, the corpus did not catch it; I added a signed claim that breaks a span rule. **JS:** with each of these mutations, `node --test` exits 1: - the session domain changed; - a pause not marked as a resumption; - a span's last visible fraction stated instead of the lowest; - 16-bit lengths written big-endian; - the challenge written without `origin_info`. ### Not done - The producer is not wired into a page: the room page plays no ads, and there is no browser end-to-end test of `attach()` with a real `IntersectionObserver`. - `IntersectionObserver` does not see what other elements cover the player; §10 says so. - Tokens of type 0x0001 cannot be verified by the reference, since only the issuer can verify them. - No issuance flow: no claim from a real device. The corpus tokens are signed with the RFC's published test key. - Invalid-traffic classes are not modelled. - §13 states that a vouched device running modified software still signs whatever it is told to. ### Existing issue on main (not in this PR) `WAI_NAME_DENYLIST=… scripts/check-public-names.sh` over all of `wai/` reports hits in `wai/wai-rs/src/live_provenance.rs` (lines 381–402, 648, 657, 1780–1781), which came from #381. That file is untouched here. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
A player's signed claim (WPC1) that it presented one impression of a live-ads
break: the creative's objects it presented, spans of its media time with the
fraction of pixels in view and audibility, the geometry they were measured over,
a rendered-frame count, and an optional RFC 9577 token bound to the impression
through its challenge and verified as RFC 9578 §6.4 does for type 0x0002.
An ad policy of version 2 requires claims (and optionally an attestation and an
audible run) under the video or cross-media viewability rule; the room
verifier's spend-equivalence then counts only impressions whose claim verifies.
The corpus live-conformance/presentation/ is generated from fixed seeds.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
extensions/ad-presentation.md defines the WPC1 claim, the session a session key
names, the creative digest, the video and cross-media viewability rules as their
texts state them, the quartile, the RFC 9577 token bound to one impression and
verified as RFC 9578 §6.4 has it, the presentation fields of a WAP1 policy of
version 2, and each claim's verdict; live-ads.md takes the version and the spend
that counts. ad_presentation_verify.py is written from the text, verifies RFC
9578's own vector, gives every claim the corpus's verdict, and catches every
mutated copy and every check dropped from itself. The corpus gains a signed
claim that breaks a span rule.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The registry lists the record and the WPC1 magic (the export regenerated), SPEC
§5 describes the claim and the billing rule, and the CHANGELOG records them.
joule-moq-web gains web/ads/presentation.js, a span recorder over a video
element and the claim's writer and signer on WebCrypto's Ed25519, whose node
tests turn observation sequences into the corpus's claims byte for byte; no page
plays ads yet. wai-conformance runs the module's tests, the corpus test,
ad_presentation_verify.py and the producer's tests; joule-moq-web's e2e script
runs the producer's tests with the page's other unit tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge remote-tracking branch 'origin/main' into wai/ad-presentation
Some checks failed
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m43s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m18s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 26s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m2s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 2m5s
wai-pack / wai-pack · linux (pull_request) Successful in 1m25s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 19m14s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 3m2s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m49s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 5m34s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 16s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 13s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 29s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 1m52s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Failing after 14m39s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 4m47s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 11m17s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 53s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m30s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 4m27s
wai-quantum studio and desktop / desktop app · macos (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
fe66f6d2de
# Conflicts:
#	.github/workflows/wai-conformance.yml
#	wai/CHANGELOG.md
#	wai/REGISTRY.md
#	wai/SPEC.md
#	wai/live-conformance/README.md
#	wai/wai-rs/src/codecs/registry.rs
Merge origin/main into wai/ad-presentation (IETF draft, timing-test fix)
All checks were successful
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m0s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 32s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 10m19s
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Successful in 1m44s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 18m58s
wai-pack / wai-pack · linux (pull_request) Successful in 1m34s
wai-quantum studio and desktop / studio · browser (pull_request) Successful in 3m8s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m59s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 1m7s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 4m41s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 2m24s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 3m22s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 1m39s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 5m20s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 31m57s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 4m14s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 15m9s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 1m48s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 10m17s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 2m55s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 8m44s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 50m59s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 9m8s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 14m52s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 19s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 1m20s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 6m59s
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Successful in 3m20s
wai-pack / wai-pack · macos (pull_request) Successful in 1m17s
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 2m54s
b2f22ea8c4
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merge origin/main into wai/ad-presentation (access services)
Some checks failed
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / does this change touch it (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / builds · no adapter is not a pass (linux) (pull_request) Has been cancelled
wai-ops-gpu integer operators on GPUs / Metal GPU and browser WebGPU (macos) (pull_request) Has been cancelled
WAI energy receipts / does this change touch it (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux (pull_request) Has been cancelled
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Has been cancelled
WAI energy receipts / energy receipts · macos (pull_request) Has been cancelled
WAI conformance / does this change touch it (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · macos (pull_request) Has been cancelled
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Has been cancelled
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Has been cancelled
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Has been cancelled
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Has been cancelled
WAI conformance / cross-arch byte-equality · macos (pull_request) Has been cancelled
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Has been cancelled
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Has been cancelled
standards workspaces build + test / which workspaces this change touches (pull_request) Has been cancelled
standards workspaces build + test / macOS energy backends (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-relay, every target (pull_request) Has been cancelled
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Has been cancelled
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Has been cancelled
58ce842e5b
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!398
No description provided.