Select replay gates from sampled event clocks

Merged
JS
17h ago
+5277-179

Adds the offline half of replay gate verification: given finalized, drained evidence, decide whether injected audio can be attributed to a tool or hint gate, and say unknown instead of aligned whenever the sampled clocks cannot order the events. A candidate acknowledgement is selected from sampled event clocks and then verified against the whole pinned process, room and session: a newer boundary, a replacement, a discarded socket, a terminal state or a stale age invalidates it, and an event that overlaps injection stays unknown.

To give the verifier intervals instead of instants, the room loop now records whether the interview is closing, logs a requested end before the farewell, and stamps each gate boundary with when it was handled as well as when it arrived, so an interruption queued behind a tool send cannot sort before the acknowledgement it followed. Observation lines are written once instead of field by field. The series also carries a fix for valid raw PCM whose first bytes only resemble a container signature (d2 c9 c6 c6 read as RIFF once the high bits were cleared), and the earlier fixture, evidence-retention and clock-correlation commits it builds on.

Verified with the full local gate (scripts/test.sh) on the rebased tip, the replay and floor-capture Node suites, the livekit Rust tests, and the Rust style check. Guard removals fail the new tests, including the queued-boundary and boundary-spanning-the-window cases. Not run: desktop checks that need WebKitGTK, and cargo-deny.

The helpers are not wired into a replay adapter yet, so no live interview or provider is exercised, and no endpointing, recovery, tool response or scoring policy changes. Left for follow-ups: emitting socket replacement and discard as gate boundaries from the producer instead of reading pressure summaries, deriving the JS tool and stage vocabulary from the Rust side, and a dedup key that tolerates two identical gate lines in one millisecond.


Summary by cubic

Adds the offline half of replay gate verification: given finalized diagnostic evidence, decide whether injected audio can be attributed to a tool or hint gate, and report "unknown" whenever sampled clocks cannot order the events. A candidate acknowledgement is selected from sampled event clocks and verified against the whole pinned process, room and session; a newer boundary, a replacement, a discarded socket, a terminal state, or a stale age invalidates it, and events overlapping injection stay unknown. This also adds named fixture validation, diagnostic stream retention, and clock correlation as the supporting pieces.

These helpers are not wired into a replay adapter yet, so no live interview, provider, endpointing, recovery, or scoring behavior changes.

Evidence and timing

  • The room loop now records whether the interview is closing, logs a requested end before the farewell, and stamps each gate boundary with when it was handled and when it arrived, so an interruption queued behind a tool send cannot sort before the acknowledgement it followed.
  • Floor records carry opening, first resolution, and candidate activity-end times on the interview clock; latency records carry sampled wall-clock and monotonic pairs with uncertainty.
  • Complete floor and latency streams are retained through shutdown with byte-bounded lines and drain-before-close.
  • Observation lines are written once instead of field by field.

Bug Fixes

  • Fixes valid raw PCM whose leading bytes resemble a container signature being refused: d2 c9 c6 c6 previously read as a RIFF header once the high bits were cleared.
  • Malformed floor record tests now assert the exact refusal reason instead of accepting any of six alternatives.