98 lines
6 KiB
Markdown
98 lines
6 KiB
Markdown
# live-conformance/events — live events
|
||
|
||
The corpus of [`extensions/live-events.md`](../../extensions/live-events.md) §10: `WEV1`
|
||
event records in stream order, the policies their principals are held to, and the outcome
|
||
a verifier gives them; `WEP1` policy records; and the records' bindings onto MoQ, LL-HLS
|
||
and CMAF/DASH.
|
||
|
||
**Live-event equivalence.** For each vector, a conforming verifier of the vector's room,
|
||
holding each principal to the policy the vector names for it (`policies`, else
|
||
`default_policy`) and offered `events` one at a time in the order given, reaches the
|
||
outcome the vector states (§6.4):
|
||
|
||
- `refuse`: the `reason` and the `index` of the first record refused (§6.1–§6.3, or §7's
|
||
`tally_mismatch` at the index of the `poll_close` whose stated counts the replay does not
|
||
reach);
|
||
- `gap`: no record refused, and the `gaps` (principal, first and last seq not held) in the
|
||
order found, under the code `delivery_gap` (§6.2);
|
||
- `accept`: no record refused, no gap, and every stated tally equal to the replay.
|
||
|
||
A vector that does not refuse also states each record's SHA-256 digest (§3.2). An accepted
|
||
vector states the tally (§7): each poll's state and counts, and the BLAKE3 state hash of
|
||
the `wai.feed.state` records they replay to; and each record's MSF event timeline record,
|
||
`EXT-X-DATERANGE` tag and version 1 `emsg` box (§8), which a verifier must render byte for
|
||
byte and read back to the record. A verifier that reaches another outcome, reason, index,
|
||
gap, digest, tally or rendering does not conform.
|
||
|
||
**Provenance.** Generated here: `wai_live_events_vectors gen` writes every record from
|
||
events authored in code, from fixed seeds. Each principal's key is SHA-256 of a fixed label
|
||
and the principal's index, each room id likewise, every time is a constant, and Ed25519
|
||
signing is deterministic (RFC 8032), so the file is the same bytes on every machine. The
|
||
generator asserts that each vector reaches the outcome it was written to have before it
|
||
writes it. The SCTE 35-1 sections are built to that standard's syntax, with their CRC; the
|
||
SCTE 35-2 message is a stand-in byte string, which the extension carries opaque. No
|
||
recorded data.
|
||
|
||
## Layout
|
||
|
||
One file, `vectors.json`:
|
||
|
||
- `t0_unix_us`, `pt0_ms`: the room's `t0` as microseconds since 1970 (for the MSF `t`
|
||
index and `START-DATE`), and the presentation time of `t0` in milliseconds (for
|
||
`emsg`).
|
||
- `principals`, `rooms`: the keys and room ids, by name (informative).
|
||
- `policies`: the policy records the vectors name, in hexadecimal: `default` (§5's
|
||
defaults), `authority` (the defaults with the lifecycle kinds), `chat_only` (chat,
|
||
reaction and vote) and `slow` (the defaults with `max_events` 3).
|
||
- `vectors`: each with `name`, `about`, `room`, `default_policy`, `policies` (principal
|
||
key → policy name), `events` (records in hexadecimal, in stream order), `outcome`, and
|
||
as above `reason`, `index`, `gaps`, `digests`, `tally` and `bindings` (per record:
|
||
`msf`, `daterange`, and `emsg` in hexadecimal).
|
||
- `policy_cases`: policy records (§5), each read (`accept`) or refused with its reason.
|
||
- `binding_cases`: an `input` for one `binding` (`daterange`, `emsg` in hexadecimal, or
|
||
`msf`), read back to its `record` or refused with its reason (§8).
|
||
|
||
Vectors:
|
||
|
||
- one accepted vector per kind of §4 (`kind_*`): metadata that is empty, anchored, and at the
|
||
default bound; cues of every type, with and without an SCTE-35 message of each form; chat across
|
||
scripts and at the text bound; standalone reactions exactly one window apart and targeted
|
||
ones; a poll with a changed vote, a vote after the close and a vote for no poll, closed
|
||
with its tally, and a poll left open; markers with and without an attachment; every
|
||
control command; captions of each origin; moderation decisions; take commitments; and
|
||
the lifecycle kinds under the authority's policy;
|
||
- `room_interleaved`: several principals' chains interleaved in delivery order across
|
||
three one-minute groups, with anchored events and a poll;
|
||
- `join_set_repeats` and `joiner_mid_stream`: one host's track as a continuous subscriber
|
||
receives it, with each group's first object repeating its join set (§8.2), and as a
|
||
subscriber that joins at group 1 receives it, which reports what it does not hold as
|
||
gaps;
|
||
- `chain_gap`: a chain with a seq not delivered;
|
||
- one negative control per refusal, each a single defect refused with its reason: a
|
||
flipped signature bit; three forgeries a lenient Ed25519 verifier accepts (an identity
|
||
key, its non-canonical spelling, an `R` of small order); a broken chain and a broken
|
||
genesis; a reorder; a replayed seq; `t` going back; an oversize payload; a kind not
|
||
permitted, and a lifecycle kind from a participant; the event rate and the reaction rate
|
||
exceeded; an overlong and a surrogate UTF-8 encoding; text over the bound; two
|
||
truncations; an unknown version; a bad magic, trailing bytes and a bad anchor flag;
|
||
an unknown kind and a reserved lifecycle kind; the wrong room; a malformed cue,
|
||
language tag and poll; and a stated tally the replay does not reach.
|
||
|
||
## Running
|
||
|
||
```
|
||
cd ../../wai-rs
|
||
cargo run --no-default-features --features live_events --bin wai_live_events_vectors -- verify ../live-conformance/events
|
||
cargo run --no-default-features --features live_events --bin wai_live_events_vectors -- gen ../live-conformance/events # regenerate
|
||
cargo test --no-default-features --features live_events --test live_events
|
||
cd ../live-conformance
|
||
python3 live_events_verify.py events
|
||
```
|
||
|
||
`wai_live_events_vectors verify` and `tests/live_events.rs` require the file to regenerate
|
||
byte for byte and `wai-rs` to give every case its outcome; the test also requires the
|
||
corpus to cover every kind and every reason, and the extension's §9 to list exactly the
|
||
reasons the reference reports. `live_events_verify.py` is the second implementation,
|
||
written from the extension's text and sharing no code with `wai-rs`: it gives every case
|
||
the same outcome, renders every binding itself, and requires the same coverage. Pass = an
|
||
exit status of 0 from each.
|