wai.live.ads: server-guided ad insertion for rooms — cues to HLS interstitials and DASH alternative presentations, asset lists, and the break form of wai.video.ssai (L11) #360

Merged
dcharlot merged 11 commits from wai/live-ads into main 2026-10-20 13:10:09 -04:00
Owner

What this is

Slice L11 of the live program: server-guided ad insertion (SGAI) for rooms. It adds the record wai.live.ads and gives wai.video.ssai a second receipt form, the break form. Manifests stay shared and cacheable, and each viewer's decision happens behind the asset list.

  • wai/extensions/live-ads.md (new):
    • the ad policy WAP1, signed by the room authority;
    • breaks taken from the room's signed cue events, with the post-roll annotation WAB1;
    • the HLS interstitial, closing and preload date ranges (draft-pantos-hls-rfc8216bis-22 Appendix D and Appendix F);
    • the DASH alternative-presentation events (ISO/IEC 23009-1:2026, replace and insert);
    • the HLS asset list and the DASH list MPD;
    • form 2 of the wai.video.ssai receipt;
    • verification end to end, from the events track through breaks, asset lists and receipts to spend.
  • wai-rs:
    • the new module live_ads (feature live_ads = ["live_room", "video_ssai"]) with unit tests, a corpus generator, the wai_live_ads_vectors bin and tests/live_ads.rs;
    • SsaiBreakReceipt in wai_video_ssai.rs, with its JSON carriage, its rules (check) and its tests;
    • its figure view in energy_figure.rs, under the existing profile wai:video-ssai-receipt-id.
  • live-conformance/ads/:
    • 37 rooms: 4 accepted, 1 gap and 32 refused;
    • each accepted room's HLS tags in a file of its own, NAME.m3u8;
    • a README.
  • live-conformance/live_ads_verify.py: the second implementation, written from the text alone. It shares no code with wai-rs and runs as python3 -I.
  • CI: a new step in wai-conformance.yml (lib tests for live_ads:: and wai_video_ssai::, --test live_ads, then the Python verifier), and live-ads.md added to paths:.
  • Registry: REGISTRY.md and the export (wai.live.ads, plus the magics WAP1 and WAB1 among the wire identifiers).
  • Docs: a SPEC §5 paragraph, and the wai.video.ssai row in SPEC §5 now names the two forms. Also a CHANGELOG entry and a cross-reference in live-events §1.

Design decisions and why

  1. A record of its own (wai.live.ads) beside wai.video.ssai, rather than folded into it.
    • The policy, the breaks and their renderings are checked against a room and its events track. The stitched SSAI form never reads either.
    • The impressions stay wai.video.ssai's, in a second receipt form. One decision rule and one spend rule then serve stitched and server-guided insertion alike.
  2. The mapping from a cue to its renderings (§4, §5, §6).
    • What each cue type produces:
      • An out opens a break. Its avail is the cue's planned duration_ms, or the policy's open_avail_ms when the cue states none. With neither, it is refused break_duration_unknown.
      • An in closes the open out with the same cue_id and the same author. Its duration is ⌊(t_in − t_out)/1000⌋ ms. It is refused cue_in_unmatched, break_zero_duration or cue_duration_mismatch when the in's stated duration is not 0 and disagrees.
      • A break (type 4) is closed when it is created. A zero duration is refused break_zero_duration.
      • A chapter opens nothing.
      • Overlap: an out or break while another break is open, or before the last break has ended, is refused break_overlap.
    • Post-roll: a type-4 break followed, in its author's chain, by a meta annotation WAB1 at the same t. This is the same pattern as WMS1 and WTX1. Any cue after it is refused cue_after_close.
    • Identifiers: the break's HLS ID is wai-ad- followed by the opening cue's digest in hex. It is distinct from live-events' own date range of that cue, whose ID is the bare digest. The DASH event id is the low 53 bits of the digest's first eight bytes, so a player that holds it as a double holds it exactly.
    • Times: START-DATE is floored to the millisecond, as live-events §8.3 does. Durations are written as S.mmm. DASH uses timescale 1000 with presentationTime = pt0 + ⌊t/1000⌋.
    • HLS tag contents:
      • CUE is ONCE for a mid-roll and POST,ONCE for a post-roll.
      • X-RESUME-OFFSET is the break's duration, so the viewer returns where the program resumes.
      • An out's actual end comes in a second tag with the same ID. It adds DURATION, X-RESUME-OFFSET and X-PLAYOUT-LIMIT, as §6.2.1 has a server signal the end of a range with a planned duration.
    • Cacheability: every attribute is a function of the signed cue, its annotation, the policy and t0, so every edge writes the same bytes. §6.2.4 requires identical date ranges across Media Playlists, and this satisfies it.
  3. The asset list (§7).
    • URIs are fixed per break:
      • HLS: <asset_base><ID>.json?_HLS_interstitial_id=<ID> (Appendix D.4).
      • DASH: <asset_base><ID>.mpd.
    • Creative URIs name each creative by its hash, so a served asset list binds the creative bytes the receipt names.
    • HLS uses Appendix D.2's JSON, written exactly.
    • DASH uses the 6th edition's list MPD (type="list", ImportedMPD).
    • The decision is SSAI's existing deterministic decide, unchanged. A viewer who joins a break while it runs is filled with the avail minus the offset (_HLS_start_offset). A room has no pre-roll.
    • The asset list is not signed. It is a deterministic rendering of the fill, and the receipt binds its SHA-256 and its format.
  4. Receipts (§8).
    • Form 2 names the room, the break (by cue digest), the session, the start offset, the asset-list format and digest, the avail, the slots and the funds remaining. It keeps form 1's pod hash, impressions, Merkle root, billable spend and energy figure.
    • It signs under its own domain, wai:video-ssai-break-receipt\x01, and shares the identity domain. So the energy-measurement §6.1 profile wai:video-ssai-receipt-id covers both forms, the same way package v2 shares its identity domain.
    • It is carried as JSON with "form": 2. Energy evidence uses energy-measurement §2.7's snake_case names, and the legacy label HwShunt is refused.
    • Form 1 is untouched: its signed bytes and its pinned legacy hash test are unchanged.
  5. Spend units. Prices and spend are in millionths of a minor unit, as live-metering's tariff is. The decider grant's ceiling is in minor units (live-rooms §4.5). The check is spend ≤ ceiling × 10^6, both per receipt (rule 3 of §8.5) and summed across every receipt of the room (§9.3 step 12, funds_exceeded).
  6. The decider is the principal of a room grant that the policy names by digest. That grant carries the budget. It is checked for revocation through the key log and against its window at the break's t. Its receipts must name it exactly as live-rooms §4.5 describes.
  7. Authorship: a cue by a principal whose grant does not permit cue is refused by the room itself (kind_not_permitted). There is a vector for this.
  8. A gap stops verification. With a delivery gap, the outcome is gap and only the gaps are stated, because a schedule read from part of the cues is not the room's.

What I read and could not read

  • draft-pantos-hls-rfc8216bis-22 (1 May 2026, the latest; -23 does not exist), as text: §4.4.5.1, §6.2.1, §6.2.4, Appendix D and Appendix F. Its Appendix H is a glossary. No revision from -18 to -22 has a "Date Range Schedules" appendix, so nothing maps there, and the spec says so.
  • ISO/IEC 23009-1:2026: I could not get the clause text of §5.16. What I read is the 6th-edition MPD schema (types EventType, AlternativeMPDEventType, AlternativeMPDReplaceEventType, ImportedMpdType, PresentationType) and its example MPDs G23, G29-1 and G29-2, at the schema's revision of 2026-06-13.
    • The spec says this in §6.1.
    • It writes no attribute whose value I could not justify from those sources: noJump, serviceDescriptionId, startWithOffset and clip keep their defaults. So the jump restriction and X-SNAP have no DASH mapping in this revision.
    • skipAfter without a skip control is written as the avail rounded up. I read that from the example's comment that a missing skipAfter means a viewer may skip at once.
    • returnOffset is written as the break's duration, mirroring X-RESUME-OFFSET.
    • Both of these should be checked against §5.16's text.
  • I read "MPI events" in the brief as MPD events: an EventStream in the Period, the manifest form that stays shared. This revision defines no in-band (emsg) form of the alternative-presentation event.

Checks (all green at head 29e7f07ab)

Build-host runs used ~/kani-logs/remote/rb <worktree> -- '<cmd>', both before and after merging origin/main (which brought DVR #351 in).

check command result
live_ads unit tests cargo test --locked --no-default-features --features live_ads --lib live_ads:: 5 passed
SSAI unit tests (both forms) cargo test --locked --no-default-features --features live_ads --lib wai_video_ssai:: 13 passed (the form-1 legacy pin unchanged)
corpus test cargo test --locked --no-default-features --features live_ads --test live_ads 3 passed
corpus bin cargo run -q --locked --no-default-features --features live_ads --bin wai_live_ads_vectors -- verify ../live-conformance/ads PASS regenerates byte for byte; PASS every case
figure view cargo test --locked --no-default-features --features video_ssai,receipt_claims --lib energy_figure:: 12 passed
registry lib tests cargo test --locked --no-default-features --lib registry 20 passed
vocab and container cargo test --locked --no-default-features --lib container:: 50 passed
CLI registry cargo test --locked --no-default-features --test cli_registry 6 passed
registry export cargo run -q --locked --no-default-features --bin wai -- registry export --check up to date
conformance-dir listing cargo test --locked --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int --test int_kernels_vectors every_decoded_output_states_a_sha256 passed
energy-receipts CI set cargo test --locked --no-default-features --features world,…,video_workflow,…,receipt_claims --lib --bins --test video_receipt exit 0
clippy cargo clippy --locked --no-default-features --features live_ads,receipt_claims --all-targets no new notes; see below
dependent crate cargo build --locked in wai/wai-web (uses video_workflow and receipt_claims) builds
lockfile cargo metadata --locked --offline --format-version 1 (wai-rs) ok; no dependency added, no lock changed
include/wai.h build.rs regenerates it on every build unchanged; asset_format is cbindgen:ignore
second implementation python3 -I live-conformance/live_ads_verify.py live-conformance/ads 37 rooms, 4 tag files; every mutated copy (17) fails; exit 0
other live verifiers live_events_verify.py, live_rooms_verify.py, live_moderation_verify.py PASS (live-events.md was touched)
repo checks 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.py all clean

About the clippy row: the one note in a touched file is wai_video_ssai.rs:211, a collapsible_if in form 1's verify. It is pre-existing and unchanged. Form 2's equivalent uses a let-chain.

Falsifications

All were run after committing, one mutant at a time, each then restored.

  • Rust (on the build host, cargo test --features live_ads --test live_ads every_case): each mutant exits 101 and names its vector.

    mutant result
    funds check removed funds_exceeded accepted
    decision comparison removed decision_mismatch reached asset_list_mismatch
    break_overlap removed accepted
    receipt_duplicate removed accepted
    cue_after_close removed accepted
    form-2 format rule removed receipt_format_three accepted
    work_decide_ops rule removed receipt_work_below_fill accepted
  • Python (verifier with one check removed): each exits 1 and names its vector.

    • Checks removed: funds_exceeded, asset_list_mismatch, break_overlap, cue_after_close, receipt_duplicate and decision_mismatch.
    • Form-2 rules removed: format, work ops, resolution floor, figure without class, and its own ceiling.
    • The first Python run caught a hole: the format rule had no negative control. I added one vector for each other rule of §8.5: receipt_format_three, receipt_work_below_fill, receipt_figure_without_class, receipt_below_resolution and receipt_over_its_ceiling.
  • Corpus mutations (17, all caught), in live_ads_verify.py's own suite:

    • a policy signature byte;
    • the in or the post-roll annotation withheld;
    • a stated asset list, the DASH streams and an open event;
    • a tag-file byte, and POST dropped from a tag;
    • the pod order and pt0;
    • a receipt's quartile and its session;
    • the stated spend and a chapter's stated length;
    • a duplicate receipt or the second funds receipt removed;
    • a tag file removed.

Public-text note

The HLS interstitial and preload date-range classes that Appendix D.2 and Appendix F define are protocol identifiers that contain a company name:

  • In .md, .rs and .py files, every line that holds them carries allow-name: <reason>.
  • In the corpus they appear only in the NAME.m3u8 tag files. That keeps them out of vectors.json, because JSON cannot carry the opt-out.
  • I could not run check-public-names.sh locally, since its denylist is a CI secret. CI runs it.

Not done / open items

  • DASH: check §5.16's text for skipAfter, returnOffset, noJump (the jump restriction) and snapping. There is no in-band emsg form.
  • Ad policy: one per room. There is no chaining or replacement mid-room, as moderation has.
  • Pre-roll: not defined, because a room has none.
  • Readers: there is no reader for tags or events. A verifier renders them and compares bytes.
  • Funds stated per decision: only bounded. The spec says so; the aggregate ceiling is what is checked.
  • Large dates: a START-DATE past year 9999 is written empty rather than refused (unreachable in practice).

🤖 Generated with Claude Code

## What this is Slice L11 of the live program: server-guided ad insertion (SGAI) for rooms. It adds the record `wai.live.ads` and gives `wai.video.ssai` a second receipt form, the break form. Manifests stay shared and cacheable, and each viewer's decision happens behind the asset list. - **`wai/extensions/live-ads.md`** (new): - the ad policy `WAP1`, signed by the room authority; - breaks taken from the room's signed `cue` events, with the post-roll annotation `WAB1`; - the HLS interstitial, closing and preload date ranges (`draft-pantos-hls-rfc8216bis-22` Appendix D and Appendix F); - the DASH alternative-presentation events (ISO/IEC 23009-1:2026, replace and insert); - the HLS asset list and the DASH list MPD; - form 2 of the `wai.video.ssai` receipt; - verification end to end, from the events track through breaks, asset lists and receipts to spend. - **`wai-rs`**: - the new module `live_ads` (feature `live_ads = ["live_room", "video_ssai"]`) with unit tests, a corpus generator, the `wai_live_ads_vectors` bin and `tests/live_ads.rs`; - `SsaiBreakReceipt` in `wai_video_ssai.rs`, with its JSON carriage, its rules (`check`) and its tests; - its figure view in `energy_figure.rs`, under the existing profile `wai:video-ssai-receipt-id`. - **`live-conformance/ads/`**: - 37 rooms: 4 accepted, 1 gap and 32 refused; - each accepted room's HLS tags in a file of its own, `NAME.m3u8`; - a README. - **`live-conformance/live_ads_verify.py`**: the second implementation, written from the text alone. It shares no code with wai-rs and runs as `python3 -I`. - **CI**: a new step in `wai-conformance.yml` (lib tests for `live_ads::` and `wai_video_ssai::`, `--test live_ads`, then the Python verifier), and `live-ads.md` added to `paths:`. - **Registry**: `REGISTRY.md` and the export (`wai.live.ads`, plus the magics `WAP1` and `WAB1` among the wire identifiers). - **Docs**: a SPEC §5 paragraph, and the `wai.video.ssai` row in SPEC §5 now names the two forms. Also a CHANGELOG entry and a cross-reference in live-events §1. ## Design decisions and why 1. **A record of its own (`wai.live.ads`) beside `wai.video.ssai`, rather than folded into it.** - The policy, the breaks and their renderings are checked against a room and its events track. The stitched SSAI form never reads either. - The impressions stay `wai.video.ssai`'s, in a second receipt form. One decision rule and one spend rule then serve stitched and server-guided insertion alike. 2. **The mapping from a cue to its renderings (§4, §5, §6).** - **What each cue type produces:** - An **out** opens a break. Its avail is the cue's planned `duration_ms`, or the policy's `open_avail_ms` when the cue states none. With neither, it is refused `break_duration_unknown`. - An **in** closes the open out with the same `cue_id` and the same author. Its duration is ⌊(t_in − t_out)/1000⌋ ms. It is refused `cue_in_unmatched`, `break_zero_duration` or `cue_duration_mismatch` when the in's stated duration is not 0 and disagrees. - A **break** (type 4) is closed when it is created. A zero duration is refused `break_zero_duration`. - A **chapter** opens nothing. - **Overlap**: an out or break while another break is open, or before the last break has ended, is refused `break_overlap`. - **Post-roll**: a type-4 break followed, in its author's chain, by a `meta` annotation `WAB1` at the same `t`. This is the same pattern as WMS1 and WTX1. Any cue after it is refused `cue_after_close`. - **Identifiers**: the break's HLS `ID` is `wai-ad-` followed by the opening cue's digest in hex. It is distinct from live-events' own date range of that cue, whose `ID` is the bare digest. The DASH event id is the low 53 bits of the digest's first eight bytes, so a player that holds it as a double holds it exactly. - **Times**: `START-DATE` is floored to the millisecond, as live-events §8.3 does. Durations are written as `S.mmm`. DASH uses timescale 1000 with `presentationTime = pt0 + ⌊t/1000⌋`. - **HLS tag contents**: - `CUE` is `ONCE` for a mid-roll and `POST,ONCE` for a post-roll. - `X-RESUME-OFFSET` is the break's duration, so the viewer returns where the program resumes. - An out's actual end comes in a second tag with the same `ID`. It adds `DURATION`, `X-RESUME-OFFSET` and `X-PLAYOUT-LIMIT`, as §6.2.1 has a server signal the end of a range with a planned duration. - **Cacheability**: every attribute is a function of the signed cue, its annotation, the policy and `t0`, so every edge writes the same bytes. §6.2.4 requires identical date ranges across Media Playlists, and this satisfies it. 3. **The asset list (§7).** - URIs are fixed per break: - HLS: `<asset_base><ID>.json?_HLS_interstitial_id=<ID>` (Appendix D.4). - DASH: `<asset_base><ID>.mpd`. - Creative URIs name each creative by its hash, so a served asset list binds the creative bytes the receipt names. - HLS uses Appendix D.2's JSON, written exactly. - DASH uses the 6th edition's list MPD (`type="list"`, `ImportedMPD`). - The decision is SSAI's existing deterministic `decide`, unchanged. A viewer who joins a break while it runs is filled with the avail minus the offset (`_HLS_start_offset`). A room has no pre-roll. - The asset list is not signed. It is a deterministic rendering of the fill, and the receipt binds its SHA-256 and its format. 4. **Receipts (§8).** - Form 2 names the room, the break (by cue digest), the session, the start offset, the asset-list format and digest, the avail, the slots and the funds remaining. It keeps form 1's pod hash, impressions, Merkle root, billable spend and energy figure. - It signs under its own domain, `wai:video-ssai-break-receipt\x01`, and shares the identity domain. So the energy-measurement §6.1 profile `wai:video-ssai-receipt-id` covers both forms, the same way package v2 shares its identity domain. - It is carried as JSON with `"form": 2`. Energy evidence uses energy-measurement §2.7's snake_case names, and the legacy label `HwShunt` is refused. - Form 1 is untouched: its signed bytes and its pinned legacy hash test are unchanged. 5. **Spend units.** Prices and spend are in millionths of a minor unit, as live-metering's tariff is. The decider grant's ceiling is in minor units (live-rooms §4.5). The check is spend ≤ ceiling × 10^6, both per receipt (rule 3 of §8.5) and summed across every receipt of the room (§9.3 step 12, `funds_exceeded`). 6. **The decider** is the principal of a room grant that the policy names by digest. That grant carries the budget. It is checked for revocation through the key log and against its window at the break's `t`. Its receipts must name it exactly as live-rooms §4.5 describes. 7. **Authorship**: a cue by a principal whose grant does not permit `cue` is refused by the room itself (`kind_not_permitted`). There is a vector for this. 8. **A gap stops verification.** With a delivery gap, the outcome is `gap` and only the gaps are stated, because a schedule read from part of the cues is not the room's. ## What I read and could not read - **`draft-pantos-hls-rfc8216bis-22`** (1 May 2026, the latest; -23 does not exist), as text: §4.4.5.1, §6.2.1, §6.2.4, Appendix D and Appendix F. **Its Appendix H is a glossary.** No revision from -18 to -22 has a "Date Range Schedules" appendix, so nothing maps there, and the spec says so. - **ISO/IEC 23009-1:2026**: I could not get the clause text of §5.16. What I read is the 6th-edition MPD schema (types `EventType`, `AlternativeMPDEventType`, `AlternativeMPDReplaceEventType`, `ImportedMpdType`, `PresentationType`) and its example MPDs G23, G29-1 and G29-2, at the schema's revision of 2026-06-13. - The spec says this in §6.1. - It writes no attribute whose value I could not justify from those sources: `noJump`, `serviceDescriptionId`, `startWithOffset` and `clip` keep their defaults. So the jump restriction and `X-SNAP` have no DASH mapping in this revision. - `skipAfter` without a skip control is written as the avail rounded up. I read that from the example's comment that a missing `skipAfter` means a viewer may skip at once. - `returnOffset` is written as the break's duration, mirroring `X-RESUME-OFFSET`. - Both of these should be checked against §5.16's text. - I read **"MPI events"** in the brief as MPD events: an `EventStream` in the Period, the manifest form that stays shared. This revision defines no in-band (`emsg`) form of the alternative-presentation event. ## Checks (all green at head 29e7f07ab) Build-host runs used `~/kani-logs/remote/rb <worktree> -- '<cmd>'`, both before and after merging origin/main (which brought DVR #351 in). | check | command | result | |---|---|---| | live_ads unit tests | `cargo test --locked --no-default-features --features live_ads --lib live_ads::` | 5 passed | | SSAI unit tests (both forms) | `cargo test --locked --no-default-features --features live_ads --lib wai_video_ssai::` | 13 passed (the form-1 legacy pin unchanged) | | corpus test | `cargo test --locked --no-default-features --features live_ads --test live_ads` | 3 passed | | corpus bin | `cargo run -q --locked --no-default-features --features live_ads --bin wai_live_ads_vectors -- verify ../live-conformance/ads` | PASS regenerates byte for byte; PASS every case | | figure view | `cargo test --locked --no-default-features --features video_ssai,receipt_claims --lib energy_figure::` | 12 passed | | registry lib tests | `cargo test --locked --no-default-features --lib registry` | 20 passed | | vocab and container | `cargo test --locked --no-default-features --lib container::` | 50 passed | | CLI registry | `cargo test --locked --no-default-features --test cli_registry` | 6 passed | | registry export | `cargo run -q --locked --no-default-features --bin wai -- registry export --check` | up to date | | conformance-dir listing | `cargo test --locked --no-default-features --features neural_int,video_int,audio_int,world_int,splat_int --test int_kernels_vectors every_decoded_output_states_a_sha256` | passed | | energy-receipts CI set | `cargo test --locked --no-default-features --features world,…,video_workflow,…,receipt_claims --lib --bins --test video_receipt` | exit 0 | | clippy | `cargo clippy --locked --no-default-features --features live_ads,receipt_claims --all-targets` | no new notes; see below | | dependent crate | `cargo build --locked` in `wai/wai-web` (uses `video_workflow` and `receipt_claims`) | builds | | lockfile | `cargo metadata --locked --offline --format-version 1` (wai-rs) | ok; no dependency added, no lock changed | | include/wai.h | build.rs regenerates it on every build | unchanged; `asset_format` is `cbindgen:ignore` | | second implementation | `python3 -I live-conformance/live_ads_verify.py live-conformance/ads` | 37 rooms, 4 tag files; every mutated copy (17) fails; exit 0 | | other live verifiers | `live_events_verify.py`, `live_rooms_verify.py`, `live_moderation_verify.py` | PASS (live-events.md was touched) | | repo checks | `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.py` | all clean | About the clippy row: the one note in a touched file is `wai_video_ssai.rs:211`, a `collapsible_if` in form 1's `verify`. It is pre-existing and unchanged. Form 2's equivalent uses a let-chain. ## Falsifications All were run after committing, one mutant at a time, each then restored. - **Rust** (on the build host, `cargo test --features live_ads --test live_ads every_case`): each mutant exits 101 and names its vector. | mutant | result | |---|---| | funds check removed | `funds_exceeded` accepted | | decision comparison removed | `decision_mismatch` reached `asset_list_mismatch` | | `break_overlap` removed | accepted | | `receipt_duplicate` removed | accepted | | `cue_after_close` removed | accepted | | form-2 format rule removed | `receipt_format_three` accepted | | `work_decide_ops` rule removed | `receipt_work_below_fill` accepted | - **Python** (verifier with one check removed): each exits 1 and names its vector. - Checks removed: `funds_exceeded`, `asset_list_mismatch`, `break_overlap`, `cue_after_close`, `receipt_duplicate` and `decision_mismatch`. - Form-2 rules removed: format, work ops, resolution floor, figure without class, and its own ceiling. - The first Python run caught a hole: the format rule had no negative control. I added one vector for each other rule of §8.5: `receipt_format_three`, `receipt_work_below_fill`, `receipt_figure_without_class`, `receipt_below_resolution` and `receipt_over_its_ceiling`. - **Corpus mutations** (17, all caught), in `live_ads_verify.py`'s own suite: - a policy signature byte; - the in or the post-roll annotation withheld; - a stated asset list, the DASH streams and an open event; - a tag-file byte, and `POST` dropped from a tag; - the pod order and `pt0`; - a receipt's quartile and its session; - the stated spend and a chapter's stated length; - a duplicate receipt or the second funds receipt removed; - a tag file removed. ## Public-text note The HLS interstitial and preload date-range classes that Appendix D.2 and Appendix F define are protocol identifiers that contain a company name: - In `.md`, `.rs` and `.py` files, every line that holds them carries `allow-name: <reason>`. - In the corpus they appear only in the `NAME.m3u8` tag files. That keeps them out of `vectors.json`, because JSON cannot carry the opt-out. - I could not run `check-public-names.sh` locally, since its denylist is a CI secret. CI runs it. ## Not done / open items - **DASH**: check §5.16's text for `skipAfter`, `returnOffset`, `noJump` (the jump restriction) and snapping. There is no in-band `emsg` form. - **Ad policy**: one per room. There is no chaining or replacement mid-room, as moderation has. - **Pre-roll**: not defined, because a room has none. - **Readers**: there is no reader for tags or events. A verifier renders them and compares bytes. - **Funds stated per decision**: only bounded. The spec says so; the aggregate ceiling is what is checked. - **Large dates**: a `START-DATE` past year 9999 is written empty rather than refused (unreachable in practice). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
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]>
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]>
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 remote-tracking branch 'origin/main' into wai/live-ads
All checks were successful
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 1m23s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 6m59s
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Successful in 4s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 5s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 5s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 6s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 2m38s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 14m58s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m37s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 2m55s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 16s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m6s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 20m13s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 3m45s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 50s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 6m57s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 12m5s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 17s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points, provenance, the semantic path (pull_request) Successful in 39s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m32s
wai-pack / wai-pack · macos (pull_request) Successful in 59s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m11s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 30s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 8m8s
wai-pack / wai-pack · linux (pull_request) Successful in 2m6s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 3m34s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 18m31s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 4m41s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m34s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m42s
29e7f07ab5
# Conflicts:
#	wai/CHANGELOG.md
Merge remote-tracking branch 'origin/main' into wai/live-ads
Some checks failed
wai-pack / wai-pack · linux-arm64 (pull_request) Has been cancelled
wai-pack / wai-pack · macos (pull_request) Has been cancelled
wai-pack / wai-pack · independent verifier (Python) (pull_request) Has been cancelled
wai-pack / wai-pack · the floor through a media prober (pull_request) Has been cancelled
wai-pack / wai-pack · dependency licences (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · every patch and mutation in exactly one shard (pull_request) Has been cancelled
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Has been cancelled
WAI HTTP delivery / cache rules · controls and labelled caches (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 / cargo-class corpora · linux (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 / macOS energy backends (pull_request) Has been cancelled
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Has been cancelled
joule-moq-web browser client / joule-moq-web · does this change touch it (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 · does this change touch it (pull_request) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (pull_request) Has been cancelled
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Has been cancelled
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Has been cancelled
1ae28b8407
# Conflicts:
#	.github/workflows/wai-conformance.yml
#	wai/CHANGELOG.md
#	wai/REGISTRY.md
#	wai/SPEC.md
#	wai/live-conformance/README.md
#	wai/wai-rs/Cargo.toml
#	wai/wai-rs/src/codecs/registry.rs
#	wai/wai-rs/src/lib.rs
#	wai/wai-rs/tests/int_kernels_vectors.rs
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!360
No description provided.