Skip to content

feat(moq-mux): catalog delay measures cross-track encoder lateness - #4123

Merged
kixelated merged 2 commits into
mainfrom
quest/m1/jitter-flush-clock
Sep 25, 2026
Merged

kixelated merged 2 commits into
mainfrom
quest/m1/jitter-flush-clock

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Works /quest/m1/jitter-flush-clock.md. This is a draft because the quest's open question decides what the new delay catalog field means. That is a wire-semantics call for the maintainer.

Problem

#3940 landed per-rendition flush jitter. What remains is the cross-track delay field and Sync sizing. The quest says to settle one question before implementing. delay is a lifetime maximum measured against a sliding broadcast baseline, so once the earliest rendition changes, the advertised values stop sharing an origin. Example: A starts at 0 and B at 200 ms, so B keeps delay: 200. If A then drifts to 500 ms, it advertises 300. The player formula max(delay + jitter) - min(delay) then gives 100 ms, while the tracks are actually 300 ms apart.

Approach

This PR only rewrites the quest's Plan. It drops the bullets #3940 already landed and replaces the open question with four options.

Option Wire meaning Never-lower Catalog can under-buffer Cost
No subtraction (recommended) Max lateness above the broadcast's earliest rendition. Consumers MUST NOT subtract across renditions. Kept No Over-buffers by min(delay) when the leading rendition isn't subscribed. A video-only viewer pays audio's lead.
Fixed common origin Lateness above the broadcast's first lateness Kept No Common clock drift grows every value without bound and republishes the catalog forever.
Coordinated rebasing Current offset, which may fall Dropped for delay No Catalog churn. The player must shrink its buffer safely.
No delay field None. The player measures each track's arrival baseline itself. n/a n/a A slower rendition glitches once on subscribe, before its offset is measured.

Why no subtraction:

  • It can't under-buffer. The subscribed renditions' spread is measured from the earliest subscribed baseline, which is never earlier than the broadcast baseline. So the spread never exceeds the largest advertised delay.
  • It keeps the sliding window, so values stay bounded under drift, and it keeps never-lower.
  • It needs no call-site changes, because the existing flush calls already feed it.
  • It removes the quest's catalog-driven re-anchor rule from Sync.

Whichever option is chosen, there is a separate receiver-side problem. Sync.received only ever lowers its reference, so if the leading track drifts later, the other tracks under-buffer. That fits with the arrival minimum that the audio jitter target line already expires.

Impact

  • No code, public API, or wire change in this PR.
  • The quest's intended surface is unchanged: an additive delay field in hang, @moq/hang, and the draft; never-lower errors extended to it; and a Sync output rename in @moq/watch.

Alternatives

Implementing the recommended option now. Not done, for two reasons. It fixes the meaning of a wire field and changes the Goal's player formula, and the quest asks for the question to be settled first. Also, #3954 on the audio jitter target line (#3952) changes what Sync.register() takes, so the player half should build on whichever lands first.

Follow-ups

  • Pick an option. If it isn't subtraction, adjust the Goal's max(delay + jitter) - min(delay) formula. This branch then continues with the implementation.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits September 25, 2026 00:46
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review September 25, 2026 14:20
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 10 minutes.

Check out review usage here.

View limit details

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

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

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: fa5fa9e3-91b5-49a7-8a58-6a59e8c816e1

📥 Commits

Reviewing files that changed from the base of the PR and between 75d615d and 3b3cb91.

📒 Files selected for processing (1)
  • quest/m1/jitter-flush-clock.md

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

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T14:22:51.560627Z 3b3cb91 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3b3cb910b6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +77 to +81
Every option also needs the player's reference to follow the earliest
subscribed track's current arrival rather than its lifetime minimum, since
`Sync.received` only ever lowers it; that is receiver-side and belongs with
the arrival minimum the [audio jitter target](/quest/m0/audio-jitter-target/README.md)
already expires.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Make the receiver reference fix a prerequisite

When the currently leading track drifts later, the catalog buffer alone cannot prevent late playback because Sync.received() retains the old, earlier reference. These lines say every option needs the audio-jitter quest's expiring arrival minimum, but this quest has no Required section and later says to build on whichever lands first, so it can ship first without that fix and under-buffer exactly this scenario. Keep the reference update in this quest or add the audio-jitter target as a prerequisite. quest/CLAUDE.mdL63-L66

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Leaving this as written.

The receiver reference stays on the audio jitter target. Its watch quest replaces the lifetime arrival minimum with a media-time window, which is the fix for Sync.received only ever lowering. Pulling that update into this quest would duplicate it.

A Required entry would block the whole quest, including the catalog delay field, until both the watch and native jitter buffers land. The measurement does not depend on the player reference.

"Build on whichever lands first" is only about #3954 changing what register() takes. That PR is merged on the audio jitter target line, not on main, so the player half still follows whichever register() shape is on the base when it starts. It is not permission to ship the player without the expiring arrival minimum.

(Written by Grok 4.7)

@kixelated
kixelated merged commit 5217cb8 into main Sep 25, 2026
3 checks passed
@kixelated
kixelated deleted the quest/m1/jitter-flush-clock branch September 25, 2026 14:53
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