Skip to content

Replay the publisher's largest group at tune-in - #8844

Open
kixelated wants to merge 2 commits into
mainfrom
quest/m2/audio-playout/replay-largest
Open

kixelated wants to merge 2 commits into
mainfrom
quest/m2/audio-playout/replay-largest

Conversation

@kixelated

@kixelated kixelated commented Nov 15, 2026 •

Copy link
Copy Markdown
Collaborator

Finishes quest/m2/audio-playout/replay-largest.md (file deleted here).

Summary

The audio-quality replay now measures a join's backlog the way a live player does. Since moq-dev/moq#8761 both consumers report a group they skip unread as join backlog when it is at or below the publisher's largest group at subscribe time, but the replay's local track only learned its largest from the first group to land (relay-mic-rtt40's stale tune-in frame, 7499), so nothing was reported.

  • Trace gains a required largest and goes to version 4. Every checked-in trace carries one, derived: the newest group whose first frame's media timestamp plus the trace's lowest lag falls at or before the first arrival (relay-mic-rtt40: 8994; bursty-aac 37665, local-aac 42, relay-bbb 10065, relay-mic and relay-mic-stall 32142). Each source names the derivation; no arrival row changed.
  • New captures record it: capture.ts joined() reads the subscription's largest() the way js/hang's consumer does (after the info or first group shows it established and start() resolved). recorder.ts and record.ts write it into the trace; the --capture observer exposes it as Capture.largest() and the probe reports it as environment.largest, so the diagnosing-live-rows recipe has it.
  • js/watch/src/audio/replay.ts: Options.largest wraps the local subscriber so largest() answers the trace's value first, then each newer group as it lands, and delegates everything else. test/audio-quality/clients/js/replay.ts passes the trace's.
  • budgets.json: only relay-mic-rtt40 moved, and is re-budgeted; the note drops the sentence about the stale tune-in frame. test/audio-quality/README.md documents the field, the capture and the derivation.
relay-mic-rtt40 before after
target p95 ms 320 120
underruns/min 0.3 0.7
player skips/min 0.3 0
trimmed ms/min 83 0
A/V lag p50 / p95 ms 0.6 / 6.9 2.3 / 8.6

The other five replay rows are unchanged to the digit.

Public API

No public API or wire change. @moq/net and the container consumer are untouched. Internal test support only: Options.largest and answering in js/watch/src/audio/replay.ts (@internal), the trace schema, and the harness's recorder.

Decisions

Choices a review can undo, taken on the maintainer's behalf (AFK):

  1. replay()'s Options.largest is optional (omitted keeps the track's own largest), while Trace.largest is required. Synthetic unit-test traces have no tune-in to model; the checked-in traces always pass it. Alternative: require it in Options too and give every synthetic test a value.
  2. answering is exported and unit-tested directly rather than through an end-to-end join scenario: the join's effect needs the cursor to skip ahead of late backlog (the shape of relay-mic-rtt40's first seconds), and the harness row already grades that and fails on a regression.
  3. A Proxy wraps the local subscriber (a Subscriber has private fields, so prototype delegation breaks); methods are bound to the target.
  4. Beyond the plan's literal list: Environment.largest through probe.ts, so a --capture row carries the join for the conversion recipe; Capture keeps the first subscription's value across a rerun.
  5. record.ts throws if the subscription never reports a largest, rather than writing a trace without one; replay.ts accepts only version 4.
  6. The derivation reads the group's first frame timestamp; taking the last frame's gives the same group on all six traces, and 9047 instead of 8994 measures the same relay-mic-rtt40 row (target p95 120).

Validation

  • just test audio-quality --replays --enforce: within budget; the six rows' table matches the quest's local measurement.
  • bun test js/watch/src/audio/replay.test.ts (new answering test) and test/audio-quality/clients/js/src/capture.test.ts (new join test: a later live group does not move Capture.largest()); just check and just fix pass.
  • Sensitivity: relay-mic-rtt40 with largest 9047 instead of 8994 replays to the same 120 ms target.
  • Not run: a live just test audio-quality-record (needs the public relay and a person at the microphone), so recorder.ts's joined() is covered by the capture test only.

Follow-ups

None.

Models

Size: S
Implementer: Claude Code, claude-sonnet-5-5, unknown effort (arm B)

🤖 Generated with Claude Code

Review

Rewritten by quest review after each round.

  • Head: fd9641d

  • Base: origin/main at ca88fc1

  • Risk: medium, the base has no RISK.md to name what is always high or customer-facing, so every change is medium

  • Classified: medium by default

  • Reviewer: Codex, gpt-6.1-sol, medium effort

  • Session: 01a1dfa8-52ed-7973-a26e-5d856c4df8d1, round 1

  • Score: 9/10, No actionable defects were found in the replay and recording changes, but validation was source-only with no builds or tests run.

  • Rounds: 1; first round 0; findings 0: fixed 0, refuted 0, open 0

  • Findings: none

kixelated and others added 2 commits November 15, 2026 06:21
…rgest group

Each trace carries the publisher's largest group as the subscription began
(version 4), and the replay answers it from the subscriber's largest() as a
wire subscriber does, so the consumer reports the join's skipped backlog.
relay-mic-rtt40's target p95 falls from 320 to 120 ms and its row is
re-budgeted. The recorder and the capture observer record the field; the
checked-in traces derive it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review November 15, 2026 14:42
@coderabbitai

coderabbitai Bot commented Nov 15, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 20 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a0ac356f-58f6-4b72-83e6-9f6a58629bbf
Commits

Reviewing files that changed from the base of the PR and between 505a86f and fd9641d.

Files selected for processing: 18

  • js/watch/src/audio/replay.test.ts
  • js/watch/src/audio/replay.ts
  • quest/m2/audio-playout/replay-largest.md
  • test/audio-quality/README.md
  • test/audio-quality/budgets.json
  • test/audio-quality/clients/js/record.ts
  • test/audio-quality/clients/js/replay.ts
  • test/audio-quality/clients/js/src/capture.test.ts
  • test/audio-quality/clients/js/src/capture.ts
  • test/audio-quality/clients/js/src/probe.ts
  • test/audio-quality/clients/js/src/recorder.ts
  • test/audio-quality/clients/js/src/schema.ts
  • test/audio-quality/traces/bursty-aac.json
  • test/audio-quality/traces/local-aac.json
  • test/audio-quality/traces/relay-bbb.json
  • test/audio-quality/traces/relay-mic-rtt40.json
  • test/audio-quality/traces/relay-mic-stall.json
  • test/audio-quality/traces/relay-mic.json
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

I reviewed the full diff: the replay's tune-in largest, the trace schema bump, the recorder and capture plumbing, the re-derived traces and the re-budgeted relay-mic-rtt40 row.

  • answering proxy (js/watch/src/audio/replay.ts) — The first largest() call returns the trace's value. Later calls return only groups newer than it. Everything else passes through to the local subscriber, with methods bound to the target so private fields still resolve. This matches how js/hang's Container.Consumer reads largest(): once, after info() or the first group and start().
  • joined() (capture.ts) — Mirrors the consumer's join read and is shared by recorder.ts (written into the trace, and record.ts refuses a trace without it) and the --capture observer (Capture.largest() → environment.largest).
  • Trace schema v4 — Adds a required largest, and replay.ts now accepts only version 4. I re-ran the stated derivation on every checked-in trace: the newest group whose earliest frame timestamp plus the trace's minimum at - timestamp lands at or before the first arrival. It reproduces each value: bursty-aac 37665, local-aac 42, relay-bbb 10065, relay-mic-rtt40 8994, relay-mic and relay-mic-stall 32142.
  • Budgets — Only relay-mic-rtt40 moves, and the note records the before and after values. Replay rows are graded exactly, so CI's replay lane checks these numbers.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant