open-standards/wai/extensions/signal-health.md
Transaction Science da8dce1844
Some checks failed
WAI operation catalogue / does this change touch it (push) Successful in 1m54s
wai-key-proxy / does this change touch it (push) Successful in 1m55s
wai-audit collector and player integration / does this change touch it (push) Successful in 1m57s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 1m58s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 1m59s
wai-fleet service / does this change touch it (push) Successful in 1m58s
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 1m59s
wai-app and Create / wai-app · does this change touch it (push) Successful in 1m59s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 55s
wai-ledger service / does this change touch it (push) Successful in 1m7s
wai-sink-android native sink library / does this change touch it (push) Successful in 1m7s
wai-quantum for JavaScript / does this change touch it (push) Successful in 1m9s
wai-quantum studio and desktop / does this change touch it (push) Successful in 1m8s
WAI Studio / does this change touch it (push) Successful in 1m7s
wai-sink-swift native sink package / does this change touch it (push) Successful in 1m8s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 1m28s
wai-fleet service / service · macos (push) Successful in 42s
wai-ledger service / service · macos (push) Successful in 1m1s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 4m24s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 6m22s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Has been cancelled
joule-moq-room room service / joule-moq-room, every target (push) Has been cancelled
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
wai-audit collector and player integration / collector · linux (push) Has been cancelled
WAI operation catalogue / the catalogue and every door · linux (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
wai-key-proxy / proxy · linux (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
wai-quantum for JavaScript / javascript · linux (push) Has been cancelled
wai-quantum energy-landscape jobs / does this change touch it (push) Has been cancelled
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Has been cancelled
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Has been cancelled
wai-quantum energy-landscape jobs / the same bits · macos (push) Has been cancelled
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Has been cancelled
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Has been cancelled
wai-quantum studio and desktop / studio · browser (push) Has been cancelled
wai-quantum studio and desktop / desktop app · linux (push) Has been cancelled
wai-quantum studio and desktop / desktop app · windows (push) Has been cancelled
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Has been cancelled
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Has been cancelled
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Has been cancelled
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 14s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m11s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 5m12s
wai: signal health — what a monitor measured on an input, signed, and the switch that acts on it
A channel's operator needs to know, per input, whether the picture went black or froze, the sound
went silent, captions or cues stopped, or the transport stream broke; and an input switch needs
that answer from a monitor it can hold to account.

extensions/signal-health.md registers `wai.live.signal_health`: a monitor's signed record (WSH1)
of one input over a window with up to six checks: black and freeze over the decoded luma, silence
in 10 ms blocks, caption and cue gaps, and the first-priority indicators of ETSI TR 101 290 V1.4.1
(sync lost with its five-and-two hysteresis, bad sync bytes, PAT_error_2, continuity, PMT_error_2,
PID_error). Each check states its thresholds, its integer values, the digest of the media it read
and its verdict. A verifier holds each verdict to its values and thresholds and each threshold to
the profile it expects with no media, and recomputes every value with it; an input switch carries
the first input whose latest record by a trusted monitor is fresh and states no fault.

The reference is the `signal_health` module of wai-rs; the corpus is live-conformance/signal-health/
(41 records, 26 checks against a profile and their media, 10 switches), its media written from
fixed seeds with each case's values declared and held by the generator, and signal_health_verify.py
is its second implementation: 77 cases agree, 14 of 14 mutated copies fail and 30 of 30 weakened
verifiers are caught. Twelve faults planted in the reference (the verdict rule, the freeze's held
frame, the duplicate allowance, the discontinuity indicator, the profile, trust, silence over one
channel, the PAT gap, the end of the window, the sync hysteresis, the media digest, freshness) each
fail its tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-08 14:48:46 -05:00

24 KiB
Raw Permalink Blame History

WAI Extension: Signal Health

Status: Draft. Registers the record wai.live.signal_health: a monitor's signed statement of what it measured on one input over a window of time. A signal-health record (WSH1, §4) carries up to six checks: black and frozen pictures, silence, when captions and cues were last seen, and the first-priority transport-stream indicators of ETSI TR 101 290. Each check states the thresholds it was measured against, the integer values it measured, the digest of the media it read and its verdict, ok or fault. Every value is a pure integer function of that media (§5), so a verifier that holds the same media recomputes the record; one that does not holds each verdict to the values and thresholds the record states and each threshold to the profile it expects (§6). An input switch acts on the verdicts of the monitors it trusts (§7). The reference implementation is the signal_health module of wai-rs (feature signal_health); the corpus is live-conformance/signal-health/, and its second implementation is live-conformance/signal_health_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.

Texts read for this revision: ETSI TR 101 290 V1.4.1 (2020-06), clause 5.2.1 (the first-priority indicators and the sync hysteresis it proposes); ISO/IEC 13818-1 (the transport packet, the adaptation field, program-specific information); RFC 8032. A section number of one of those texts here is that revision's.

1. Scope

In scope: the checks and what each reads (§3); the record, its digest and its signature (§4); how each check's values are computed from its media (§5); what a verifier derives from a record, with or without the media (§6); and how an input switch chooses an input from the records it holds (§7).

Out of scope: decoding. A monitor reads the pictures and samples a decoder of the input's capability outputs; for a capability whose class is StandardDefined every conforming decoder outputs the same pictures (SPEC §5), so two monitors that decode one recording read the same luma, and either one's record recomputes from the other's reading. Also out of scope: how records travel, how a monitor raises an alert, how media reaches a monitor, and the second- and third-priority indicators of TR 101 290.

Relationship to the core spec: wai.live.signal_health is a record (SPEC §5). It names no payload format and is not dispatchable.

2. Terms

  • Instant: a count of milliseconds since 1970-01-01T00:00:00Z, leap seconds not counted, as holdings writes one.
  • Window: the instants from from_ms up to, not including, to_ms, that a record covers.
  • Input: one contribution to a channel or a room, named by the operator: a primary and a backup feed of one channel are two inputs.
  • Monitor: the party that measures an input and signs the record, named by its Ed25519 key.
  • Frame: the luma plane of one decoded picture, its samples 8-bit, row by row, with the instant it is presented at. A picture of more than 8 bits is read at its 8 most significant bits.
  • Run: a maximal sequence of consecutive frames, or of consecutive audio blocks, that each meet a check's condition.
  • Profile: the thresholds an operator states for its inputs, per check.

3. The checks

code name reads thresholds fault when
1 black frames luma_max, ratio_ppm, min_ms a run of black frames lasts min_ms or longer
2 freeze frames mad_milli, min_ms a run of frozen frames lasts min_ms or longer
3 silence audio peak_max, min_ms a run of silent blocks lasts min_ms or longer
4 captions caption instants max_gap_ms max_gap_ms is not 0 and the longest gap without a caption exceeds it
5 cues cue instants max_gap_ms max_gap_ms is not 0 and the longest gap without a cue exceeds it
6 transport transport stream table_max_gap_ms, pid_max_gap_ms any indicator of §5.6 counted an event

A record carries the checks its input has: an input with no audio carries no silence, and one whose captions are not monitored carries no captions. max_gap_ms 0 states when captions or cues were last seen and checks nothing: a channel's cues may be hours apart, and only an operator whose encoder sends a cue at a known interval (a splice null as a heartbeat, say) has a gap to check.

A caption is a caption cue of the input's caption track (timed-text) or a line-21 or caption-service packet in its video; a cue is a splice information section of the input (SCTE 35) or a cue event of its room (live-events). Which ones the monitor counts is its own; the record binds the instants it counted (§5.4).

4. The record

4.1 Layout

Integers are unsigned and big-endian.

size field meaning
4 magic WSH1 (ASCII)
1 version 1 in this revision
32 monitor the monitor's Ed25519 key
1 name_len 1 to 64
name_len input the input's name: ASCII letters, digits, ., _, - and :
8 from_ms u64: the window's first instant
8 to_ms u64: the instant the window ends at
1 m 1 to 6: the checks' count
… checks m checks, §4.2, in strictly increasing order of code
64 sig §4.3

4.2 A check

Every check is code (u8), media (32 bytes, the digest of the media it read, §5), then its thresholds and its values, then verdict (u8: 0 ok, 1 fault):

code thresholds values
1 black luma_max u8 · ratio_ppm u32 · min_ms u32 frames u32 · matched u32 · longest_ms u64 · longest_at_ms u64
2 freeze mad_milli u32 · min_ms u32 frames u32 · matched u32 · longest_ms u64 · longest_at_ms u64
3 silence peak_max u16 · min_ms u32 blocks u32 · matched u32 · longest_ms u64 · longest_at_ms u64
4 captions max_gap_ms u32 seen u32 · last_ms u64 · longest_gap_ms u64
5 cues max_gap_ms u32 seen u32 · last_ms u64 · longest_gap_ms u64
6 transport table_max_gap_ms u32 · pid_max_gap_ms u32 packets u64 · sync_loss u32 · sync_byte u32 · pat u32 · cc u32 · pmt u32 · pid u32

matched counts the frames or blocks that met the check's condition, longest_ms is the longest run's duration and longest_at_ms its first instant (§5); seen counts the instants read, last_ms is the last of them and longest_gap_ms the longest gap (§5.4); the six counts of transport are the indicators of §5.6.

4.3 Digest and signature

The digest of a record is SHA-256 over its bytes from magic through its last check. The signature is Ed25519 by monitor over wai:signal-health (ASCII) and 0x01, followed by the bytes the digest covers.

5. What each check computes

Every quantity here is an integer and every comparison exact. A check's media is SHA-256 over a domain string, the byte 0x01 and the media, as below; a verifier that holds the media holds it to that digest before it recomputes anything (§6.4).

5.1 Frames: black and freeze

The frames are a sequence, each its instant (u64), its width and height (u16 each, at least

  1. and its width × height luma samples. Their instants are strictly increasing and within the window. Their digest is over wai:signal-health:video, 0x01, and for each frame in order its instant (u64), width (u16), height (u16) and samples. A frame's span ends at the next frame's instant, and the last frame's at to_ms.
  • Black. A frame is black when 1 000 000 × (its samples at or below luma_max) ≥ ratio_ppm × (its samples). A run of black frames lasts from its first frame's instant to the end of its last frame's span.
  • Freeze. A frame other than the first is frozen when it has the previous frame's width and height and 1000 × Σ |its sample − the previous frame's sample at the same position| ≤ mad_milli × (its samples): its mean absolute difference from the previous picture is at most mad_milli thousandths of a code value. The first frame is never frozen. A run of frozen frames lasts from the instant of the frame before its first frame, the picture that held, to the end of its last frame's span.

frames is the frames' count and matched the black, or frozen, frames'. longest_ms is the longest run's duration and longest_at_ms the instant its duration starts at, the earliest run where two are equally long; both are 0 when no frame matched.

5.2 Audio: silence

The audio is its first sample's instant at_ms (u64), its rate (u32, a multiple of 100 from 100 to 384 000), its channels (u16, 1 to 32) and its samples, 16-bit two's complement, little-endian, interleaved, a whole number of sample frames. Its digest is over wai:signal-health:audio, 0x01, at_ms (u64), the rate (u32), the channels (u16) and the samples as given. It is cut into blocks of rate ÷ 100 sample frames, 10 ms each: block b starts at at_ms + 10b, and a last part shorter than a block is not read. at_ms is at or after from_ms, and the end of the last whole block at or before to_ms.

A block is silent when the greatest absolute value of its samples, over every channel, is at most peak_max (|−32768| is 32768). A run of silent blocks lasts 10 ms a block. blocks is the blocks' count, matched the silent blocks', and longest_ms and longest_at_ms are as in §5.1, longest_at_ms the run's first block's start.

5.3 Why peaks and means of absolute differences

A peak and a sum of absolute differences are exact in integers, need no square root, and do not depend on the order a sum is taken in, so two implementations agree to the sample. Loudness measures something else: a programme can be at its target loudness and carry a silent channel, and a quiet channel is not a silent one.

5.4 Instants: captions and cues

The instants are a sequence of u64, non-decreasing and within the window. Their digest is over wai:signal-health:captions (for cues, wai:signal-health:cues), 0x01, their count (u32) and each instant (u64). seen is their count and last_ms the last of them, 0 when there is none. The gaps are the instants' differences, in order, from from_ms to the first, from each to the next, and from the last to to_ms; with no instant, the one gap is the window. longest_gap_ms is the greatest.

5.5 The transport stream

The transport stream is its bytes, a whole number of 188-byte packets and at least one, the instant in microseconds its first packet arrived (first_us, u64) and the rate it arrived at (rate_bps, u64, at least 1). Packet k, from 0, arrived at a(k) = first_us + ⌊k × 1 504 000 000 ÷ rate_bps⌋ µs: a stream of constant rate, as a broadcast multiplex is. first_us is at or after from_ms × 1000, and the last packet's arrival before to_ms × 1000. Its digest is over wai:signal-health:transport, 0x01, first_us (u64), rate_bps (u64) and the bytes. packets is the packets' count. Every duration below is compared in microseconds, a threshold in milliseconds taken × 1000, and E is to_ms × 1000.

5.6 The indicators

The six indicators of TR 101 290 clause 5.2.1 (Table 5.0a), using its later forms 1.3.a and 1.5.a, as it recommends. Each counts events; the check's verdict is fault when any count is above 0.

Sync (1.1 sync_loss, 1.2 sync_byte). The packets are read in order, 188 bytes apart from the first byte; a packet's sync byte is good when its first byte is 0x47. TR 101 290 proposes five consecutive good sync bytes to acquire sync and two or more consecutive bad ones to lose it. So a reader starts hunting; a good sync byte adds one to its run of good ones and a bad one sets the run to 0, and at a run of 5 it is locked, and analyses (below) the five packets of the run, in order. Locked, it analyses each packet with a good sync byte; a bad one counts one sync_byte event and is not analysed, and the second of two consecutive bad ones counts one sync_loss event and returns the reader to hunting, with a run of 0. A stream whose reader is never locked counts one sync_loss event. A bad sync byte met while hunting counts nothing.

Analysis. For an analysed packet: its PID is the 13 bits after its first byte's successor's top three; scrambling its fourth byte's top two bits, afc the next two, cc the low four; pusi bit 0x40 of its second byte. With afc 2 or 3 its adaptation field's length L is its fifth byte, its discontinuity indicator is bit 0x80 of its sixth byte where L > 0, and its payload starts at byte 5 + L; with afc 1 at byte 4. It has a payload when afc is 1 or 3 and its payload starts before byte 188. A packet of PID 0x1FFF (a null packet) is not analysed further. For every other packet, in this order:

  1. Continuity (1.4 cc). A packet with a payload is held to the last cc of its PID's packets with a payload, if there is one. With its discontinuity indicator set, it is taken as it is. Otherwise, a cc equal to the last is a duplicate: TR 101 290 allows a packet to occur twice, so the PID's second consecutive duplicate, and each one after, counts one event; and a cc that is neither the last nor the last plus 1 modulo 16 counts one event (a lost or reordered packet). Anything but a duplicate sets the PID's count of consecutive duplicates to 0. The PID's last cc becomes this packet's. A packet without a payload is not held to it and leaves it as it was.
  2. The referred PIDs (1.6 pid). A PID that a program map names as an elementary stream (step 4) is referred, and has an anchor, the instant it was last seen. A packet of a referred PID arriving more than pid_max_gap_ms after the anchor counts one event; the anchor becomes its arrival.
  3. PID 0 (1.3.a pat). On PID 0, a packet whose scrambling is not 0 counts one event. A packet with pusi and a payload has a pointer field, its payload's first byte, and a section starts after it, at the payload's start + 1 + the pointer field, if that is before byte 188. A section of table_id 0x00 there is a program association section: arriving more than table_max_gap_ms after the PAT anchor, which starts at from_ms × 1000, it counts one event, and the anchor becomes its arrival. A section of another table_id there, but 0xFF (stuffing), counts one event. A program association section whose section_length is at least 9 and which ends within its packet (its 3 header bytes and section_length bytes) replaces the program map PIDs with those of its program loop (every 4-byte entry from its ninth byte to the 4 bytes of its CRC whose program_number is not 0), at its arrival. A program map PID that becomes one has its anchor at that arrival; one that stops being one is held to its anchor once more at that arrival (step 4's rule), and is forgotten.
  4. A program map PID (1.5.a pmt). On a program map PID, a packet whose scrambling is not 0 counts one event. A section of table_id 0x02 that starts in it, as on PID 0, is a program map section: arriving more than table_max_gap_ms after the PID's anchor, it counts one event, and the anchor becomes its arrival. One whose section_length is at least 13 and which ends within its packet replaces the PID's elementary PIDs with those of its stream loop: after its 12 bytes of header and its program_info_length bytes of descriptors, each entry of 5 bytes and its ES_info_length bytes, while a whole entry lies before the CRC. The referred PIDs are then every program map PID's elementary PIDs together: one that becomes referred has its anchor at this arrival; one that stops being referred is held to its anchor once more at this arrival (step 2's rule), and is forgotten. A PID forgotten as a program map PID takes its elementary PIDs out of the referred ones in the same way.

At E, the PAT anchor, each program map PID's anchor and each referred PID's anchor are held once more: each more than its gap before E counts one event. A gap is counted once, however long it lasts.

TR 101 290 makes every other indicator invalid while 1.1 is active; a record counts them for the packets it analysed, and a verifier reads them with sync_loss. Its sections' CRCs are second-priority (2.2) and are not checked here.

6. What a verifier derives

6.1 Reading

A reader reads exactly the bytes it is given as one record, in the order of §4.1, and refuses it signal_health_malformed when the bytes are more than 1024, end before a field the layout requires or go on after sig, or when:

  1. its magic is not WSH1 or its version not 1;
  2. name_len is 0 or above 64, or input holds a byte other than those §4.1 allows;
  3. from_ms is not below to_ms, or to_ms is above 2^53 − 1;
  4. m is 0 or above 6, a code is not 1 to 6, or the codes are not strictly increasing;
  5. a threshold is out of its range: ratio_ppm 1 to 1 000 000, peak_max at most 32 768, every min_ms, table_max_gap_ms and pid_max_gap_ms at least 1;
  6. a value cannot be one §5 computes: matched above frames or blocks; longest_ms above to_ms − from_ms; matched 0 and longest_ms or longest_at_ms not 0, or matched not 0 and longest_ms 0 or longest_at_ms outside the window; seen 0 and last_ms not 0 or longest_gap_ms not the window's length, or seen not 0 and last_ms outside the window; longest_gap_ms above the window's length;
  7. a verdict is not 0 or 1.

A record that reads is then refused signal_health_signature_invalid when its signature does not verify under monitor as SPEC §7 Signatures verifies every signature: a key that is not the canonical encoding of a point of large order fails, as does a signature whose scalar is not below the group order.

6.2 Verdicts

A check's verdict follows from its thresholds and values: fault exactly when the condition of §3 holds of them (for black, freeze and silence, longest_ms ≥ min_ms; for captions and cues, max_gap_ms not 0 and longest_gap_ms > max_gap_ms; for transport, a count above 0). A record one of whose checks states another verdict is refused signal_health_verdict_inconsistent. A verifier checks this with no media.

6.3 The profile

A verifier that expects a profile for the input holds the record to it: the record has a check for each check the profile names and no other, each with the profile's thresholds, or it is refused signal_health_profile_mismatch. A monitor that loosened a threshold, or left out the check that would have failed, is refused here, without the media; its record is still its word about what it measured.

6.4 Recomputing

A verifier that holds the media a check read recomputes the check, in the record's order:

  1. the media is held to §5's form for it (instants within the window, a rate that is a multiple of 100, whole packets, and so on), or the check is refused signal_health_media_malformed;
  2. the media's digest is the check's media, or signal_health_media_mismatch;
  3. the values of §5 under the check's thresholds are the check's values, or signal_health_not_recomputed.

A check whose media the verifier does not hold is not held: its values are the monitor's word, bound by its digest to the media it read. black and freeze read the same frames and carry the same digest.

7. The input switch

A switch chooses, among the inputs of one channel in its order of preference, the one to carry. It is configured with that order, the monitor keys it trusts, the profile, and max_age_ms, how old a record may be and still speak for its input. At an instant t, each record it holds is, in this order:

  • refused (§6.1 to §6.3), with the reason;
  • untrusted: its monitor is not one the switch trusts;
  • not_yet: its to_ms is after t;
  • superseded: another record of its input that stands this far has a later to_ms;
  • contradicted: another record of its input with the same to_ms has another digest;
  • otherwise it stands.

Each input is then none (no record of it stands or is contradicted), contradicted, stale (t − its record's to_ms > max_age_ms), fault, with the names of its record's faulted checks in code order, or healthy. The switch carries the first healthy input in its order; with none healthy it keeps the input it carries. It never moves to an input it cannot vouch for: an input with no fresh record is not healthy, so a monitor that stops sending records stops vouching for its input. A switch SHOULD recompute (§6.4) a record whose media it holds before it acts on it.

8. Reasons

The codes this extension adds, each with where it is raised:

reason raised at
signal_health_malformed §6.1
signal_health_signature_invalid §6.1
signal_health_verdict_inconsistent §6.2
signal_health_profile_mismatch §6.3
signal_health_media_malformed §6.4
signal_health_media_mismatch §6.4
signal_health_not_recomputed §6.4

9. Conformance

live-conformance/signal-health/ holds the corpus, written from fixed seeds by wai_signal_health_vectors gen as vectors.json. It has:

  • Records: one with all six checks healthy, and one faulted record for each check, with its digest and its faulted checks; and one negative control for each rule of §6.1, for a signature that does not verify (a non-canonical key among them) and for a verdict that does not follow from its values, each way.
  • Checks: records against a profile and against their media: each check recomputed; a black run, a freeze held by its frame before, a silent run in 10 ms blocks, caption and cue gaps at the window's edges; every transport indicator counting events (sync lost and found again, a bad sync byte, a PAT late, scrambled and of another table, a duplicate allowed and a third occurrence counted, a discontinuity taken, a lost packet, a PMT late, an elementary stream gone quiet); a threshold changed from the profile, a check left out, media that does not match its digest, media out of the window, and a value the media does not give.
  • Switches: a primary and a backup, healthy, faulted, stale, superseded, contradicted, by an untrusted monitor and refused, with the input each switch carries.

A conforming verifier gives every case the outcome, the reason and everything else the corpus states. wai_signal_health_vectors verify and the test tests/signal_health.rs check that the file regenerates byte for byte, that wai-rs gives every case its outcome, that every reason of §8 appears, and that §8 lists exactly the reference's codes; the generator declares each media case's values and requires the reference to measure them. live-conformance/signal_health_verify.py is the second implementation, written from this text: it shares no code with wai-rs; it reads records, recomputes every check from the media and runs the switch itself, mutates copies of the corpus and requires every copy to fail, and drops each of its own checks in turn and requires the corpus to catch the weakened verifier.

10. Security and privacy considerations

  • A record is its monitor's word, bound to the media it read. A verifier with the media recomputes it; one without holds the verdicts to the values (§6.2) and the thresholds to the profile (§6.3), so a monitor cannot report ok over values that fail, loosen a threshold, or drop a check, without being refused. It can misstate the values of media no one else holds; a second monitor on the same input, or a recording, is the check on that.
  • A switch moves on trusted records only. Anyone can sign a record that states a fault; a switch that acted on it would let anyone take a channel to its backup. §7 reads only the keys it is configured with, and refuses a record whose verdicts do not follow from its values.
  • Freshness: a switch treats an input with no fresh record as not healthy (§7). A monitor SHOULD sign a record a window at a time, with windows shorter than max_age_ms.
  • What a record discloses: an input's name, the window and the figures, nothing of its pictures or sound beyond the digests. A digest of media that few hold says little; one of a public broadcast can confirm that a party held a given recording.
  • Bounded work: a record is at most 1024 bytes, read once, in order; recomputing reads each frame, block and packet once and keeps state per PID, at most 8192 PIDs.