Repository navigation
The shared clock follows a lasting path-delay step - #8749
Conversation
Quest-Claim: 25d581b1c97e3fee
Each track's anchor moves later once a whole 2 s window of its arrivals trailed it by more than half the delay, in js/watch Sync and moq_mux::sync, held to one corpus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou'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 8 minutes. View limit details
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. |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
I reviewed the clock-step rule in both players, the shared corpus, and the docs. Both corpus suites pass locally: bun test js/watch/src/sync.test.ts (43 pass) and cargo test -p moq-mux --lib sync:: (33 pass).
- Lasting-step follow in
js/watchSync:Clock.followcloses 2 s tumbling windows per track and moves the anchor later once the window's least ref trails it by more than half the resolved delay. When the owner moves,handoffpasses the reference to the earliest anchor left. While startup is in progress, nothing moves. - Same rule in
moq_mux::sync:Part::followuses the same window and the same strict half-delay bound (Anchor::earlieragainstanchor + half). The reference is still the minimum over parts, so a move shows up throughmoved. - Window lifecycle:
reset,end,unanchor, andreleaseall clear the window, so a restarted timeline never inherits stale evidence. - Shared vector
clock/corpus.json: five hand-written cases (step, shallow, spike, tracks, silent) run in both languages, following thecomfort/corpus precedent. - Docs and quest:
audio-jitter.mdgains "A lasting step", andclock-step.mdis retired.
On the JS handoff: the reference only moves when owner === part. I checked the case where the owner is not the track with the earliest anchor, which can happen after the startup shift or under a lookahead cap. It still converges, because each track measures the trail against its own anchor. A shared step therefore makes the owner follow too, and each handoff passes ownership to the earliest anchor.
claude-opus-5-5 | 𝕏
# Conflicts: # quest/m2/audio-playout/README.md
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
The only change since the last review is a merge of origin/main. The clock code, the corpus and the docs are unchanged.
- Quest README after the merge: In
quest/m2/audio-playout/README.md, the merge keeps the PR's sentence that the clock step is done. It also brings in main's sentence about the join's intervals (moq-dev/moq#8730).
claude-opus-5-5 | 𝕏

Summary
After a lasting increase in path delay, the shared clock follows it, in the browser (
js/watchSync) and natively (moq_mux::sync).Until now a track's anchor (the earliest arrival minus timestamp it has seen) only ever moved earlier, while the estimator measures each frame against the fastest of the last 2 s. After a step, the estimate forgot the step within its window but the clock kept the old reference, so every frame stayed late by the step. Under the lag rule (moq-dev/moq#8722) that showed up as underruns.
The rule, for both players:
WINDOW). The arrival that closes a window counts in it and opens the next.Both players read one shared vector,
doc/concept/audio-jitter/clock/corpus.json, with five cases: step, shallow, spike, tracks, and silent.doc/concept/audio-jitter.mdgains "A lasting step". This finishesquest/m2/audio-playout/clock-step.mdand deletes it.Decisions
Each was taken by the agent under /quest-afk, for the maintainer's review.
chromium-opus-step, today's clock leaves 43% of the frames after 35 s late. With half the delay none are late, after one 56 ms move, and no other profile moves at all. Rejected:wide, 2 to 7 moves per minute, each one a skip or slowdown.step, whose 55 ms step is about the size of its 60 ms target.WINDOW, so the clock and the target measure against the same fastest frame. Rejected:congestionrows, the 1.5 s collapse and its backlog never filled a whole window.stepreruns under Validation showed no regression. Decided 2026-11-14 (maintainer, /quest-complete): ✅ mergeValidation
cargo test -p moq-mux --lib sync::(33 pass) andbun test js/watch/src/sync.test.ts(43 pass). Againstmain'ssync.ts, the corpus fails itsstepandtrackscases.just test audio-quality --replays --enforce. All six rows are unchanged and within their exact budgets.main:main→ branch)main→ branch)main, the AAC row underruns repeatedly after the step against the stale reference: at 30.7, 31.3, 48.8, 50.8 and 59.5 s.stepreruns, 13 runs interleaved on one host (fedora, debug build, seed 7, 60 s, 10:26 to 10:40):mainis the PR's merge base77c9ca5, the branch is777470d. The step is the lag's jump up, the move is the lag's drop as the reference moves later, and episodes are the analyzer's quiet-quanta gaps, on the viewer clock.main1main2main3main4main5main6main20.6 (median 6.5), branch 5.1 (median 0). Both sides swing from 0 to about 20 per minute run to run, so a single run of this row is noise.main2 has the same one, 17 quanta at 29.81 s, beside the earlier branch run's 18 at 29.75 s. Until the first window closes with every arrival past half the delay (the move, 2.25 to 2.5 s after the step), the branch's clock ismain's, so it cannot cause anything at the step.main, audio slips further behind the stale reference after the step. The median lag goes from -8 ms before the step to +12 ms at 34 to 45 s and +40 ms at 45 to 60 s (main2). The late episodes inmain3 and 5 come from that. On the branch the lag returns to about -5 to -10 ms after the move, and its p95 drops from 40 to 45 ms to 1 to 20 ms.wide. Thewideunderrun counts differ by a few quanta in each direction, within run-to-run noise on this host.mildandcongestionrows ran too; none fell outside its budget except the A/V lag keys.mainas well, which the budget note already records. That is why those keys exceed their Nightly-measured budgets here.main(with moq-dev/moq#8730's join discount):cargo test -p moq-mux --lib(2109 pass),bun test js/watch/src js/hang/src/container doc/concept(929 pass), andjust test audio-quality --replays --enforce(all six rows within budget).Impact
Caused by
No single PR. The anchor has only ever moved earlier since the shared clock was written. The lag rule (moq-dev/moq#8722) turned the stale reference from a resting offset into underruns.
Follow-ups
None.
Models
Size: M
Implementer: Claude Code, claude-opus-5-5, unknown effort
Implementer: Claude Code, claude-opus-5-5, unknown effort (iterate, XS)
(Written by Claude Opus 5.5)
Review
Rewritten by
quest reviewafter each round.Head: b714fed
Base: origin/main at 8b93ab2
Reviewer: Codex, gpt-6.1-sol, high effort
Session:
01a1da7f-5392-7d21-a96b-6d0a6ec10a10, round 2Score: 8/10,
The new head only merges main, leaves the previously reviewed implementations unchanged, and introduces no actionable findings; builds and tests were not run as instructed.Rounds: 2; findings 0: fixed 0, refuted 0, open 0
Findings: none