Skip to content

feat(moq-gst): moqsink publishes each run under a fresh epoch - #4955

Merged
kixelated merged 2 commits into
mainfrom
quest/m0/broadcast-epoch/gst
Oct 7, 2026
Merged

kixelated merged 2 commits into
mainfrom
quest/m0/broadcast-epoch/gst

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Completes the GStreamer quest of the broadcast-epoch line.

Summary

  • moqsink mints a publisher epoch in Session::start (each READY -> PAUSED run) and announces its broadcast with it, so a restarted pipeline is a clean takeover for viewers instead of a resume into the lingering old run's group sequence. Reconnects within a run keep the same epoch, so they still resume.
  • The epoch is logged at info alongside the broadcast path.
  • Regression test sink::session::tests::each_run_announces_a_newer_epoch: two runs each announce an epoch, the second newer than the first (fails without the change: no epoch on the route).
  • doc/bin/gstreamer.md describes the behavior. Paths are unchanged, since the epoch is route metadata.
  • Quest bookkeeping: deletes quest/m0/broadcast-epoch/gst.md and its references. The "each moqsink: the publication has no generation, so a flush after EOS cannot restart it #3115 generation is a new epoch" half moves into the moqsink: the publication has no generation, so a flush after EOS cannot restart it #3115 quest's plan, since that quest has not landed.

Public API and wire impact

  • Public API: none. No new element properties, no exported Rust items.
  • Wire: none new. On lite-07 sessions the announcement now carries an epoch; older versions and moq-transport see no change.

Checks

  • just check passes (152 moq-gst tests, including the new one).
  • quest check passes.

Suggested follow-ups

  • moqsrc reacting to an epoch switch mid-playback (fresh catalog, decoder reset) is not covered by any quest named for GStreamer; the Apps quest mentions "native players". Worth confirming whether moqsrc falls under it.
  • Consider a read-only epoch element property only if an application needs to correlate runs; kept private for now.

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

kixelated and others added 2 commits October 6, 2026 23:14
Session::start mints a publisher epoch and announces the broadcast with
it, so a restarted pipeline takes over from a lingering old route instead
of resuming viewers into the old run's group sequence. Reconnects within
a run keep the epoch. The epoch is logged at info.

Completes quest/m0/broadcast-epoch/gst.md; the per-generation half moves
into the #3115 quest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Outcome: the quest is complete in one small change. moqsink mints an epoch per run in Session::start; reconnects within a run keep it. No open decisions block this PR. One scope question for the maintainer: does moqsrc handling an epoch switch mid-playback belong to the Apps quest's "native players", or does it need its own quest? Recommendation: a small m0 quest under broadcast-epoch, since Apps names only moq-cli, the browser components, demo/web, moq-boy, and moq-room.

(Written by Claude Opus 5.5)

@kixelated
kixelated marked this pull request as ready for review October 7, 2026 06:21
@coderabbitai

coderabbitai Bot commented Oct 7, 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 3 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
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e564d21b-fee3-4096-b968-3bd138cfc39f
📥 Commits

Reviewing files that changed from the base of the PR and between 8ecd2ca and 93a405f.

📒 Files selected for processing (6)
  • doc/bin/gstreamer.md
  • quest/m0/broadcast-epoch/README.md
  • quest/m0/broadcast-epoch/gst.md
  • quest/m1/3021-moq-gst-anchor-generated-media-timelines-to-wall-clock.md
  • quest/m2/3115-moqsink-the-publication-has-no-generation-so-a-flush.md
  • rs/moq-gst/src/sink/session.rs
  • Autopilot · 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

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

@kixelated

Copy link
Copy Markdown
Collaborator Author

Grok review (head 93a405f)

Session::start (rs/moq-gst/src/sink/session.rs:285-289) mints Epoch::mint() once per READY -> PAUSED run and publishes with Route::default().with_epoch(epoch). I checked the surrounding code:

  • start_session in imp.rs:551 is the only caller. The reconnect loop (client.connect(...) over origin.consume()) reuses the same origin and route, so reconnects within a run keep the epoch as described. A failed PausedToReady keeps the session and its epoch. A retried start mints a new one, which is correct.
  • The new test depends on Epoch::mint() ordering two calls in the same process, which uuid::now_v7() guarantees (epoch.rs already tests the same property). The started() helper still drops the broadcast at once, as before.
  • The doc link /concept/moq-lite#publisher-epochs resolves, and no broadcast-epoch/gst.md references remain at head.

Findings (low severity, none blocking):

  1. Sinks that publish replicas of the same path can no longer share an instance. Before this change, two moqsinks publishing the same path (a hot standby, or two encoders pushing the same content for cost-based failover) both had epoch-less routes and resolved by cost. Now each mints its own epoch. Per doc/concept/moq-lite.md §Publisher epochs, starting the second one is a Replacement: subscriptions on the first end with Unroutable, and viewers move to a different group sequence. This is correct for "restart", but there is no opt-out. If anyone runs moqsink in a replica setup, a writable epoch property (unset = mint per run) would cover it. It would be worth one line in doc/bin/gstreamer.md saying that two sinks on one path now replace rather than share.
  2. Clock-skew caveat. A restart on a host whose clock runs behind the old run's host loses to the lingering old route until that route retracts. The concept doc already covers this, so it's fine as is. I mention it only because the gstreamer doc now promises viewers switch "at once".

CI: Check, Test, Quest, macOS, and Windows all pass.

Verdict: MERGE (reviewed head 93a405f1)

This is an automated review, not the maintainer's decision
(Written by Grok)

@kixelated kixelated left a comment

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.

Automated review by review (OpenAI)

Reviewed commit: 93a405f

No new actionable correctness findings. rs/moq-gst/src/sink/session.rs:285-305 mints once before the reconnect loop takes the origin; reconnects retain that route, while READY → PAUSED creates a fresh session. The regression test at :563-574 checks route epochs and increasing identity. Direction is sound and appropriately leaves publication-generation handling with #3115 and source-side cutover with #4960.

Verification: inspected all six changed files, surrounding session/state-transition code, Epoch::mint and existing discussion. The new test is a useful local invariant test, not an end-to-end restart/reconnect test. No tests run here; the status endpoint returned no commit statuses, so I have not independently verified the reported CI results.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary for head 93a405f1f715a6809965fcf3400e5cb0f6f0f20d.

Changes: moqsink mints a publisher epoch in Session::start, so each run from READY announces a fresh epoch and reconnects within a run keep it. A regression test checks that a second run announces a newer epoch. doc/bin/gstreamer.md documents the behavior. The finished broadcast-epoch/gst.md quest is removed, and #3115 now notes that each generation mints its own epoch.

Review findings: the OpenAI review has no findings. Grok's two low-severity notes don't block the merge:

  • Replica sinks on one path now replace each other instead of sharing by cost. That is what the quest set out to do (a fresh epoch per run). If a replica use case shows up, a writable epoch property can follow later.
  • The clock-skew caveat is already covered in the concept doc's publisher-epochs section.

CI is green and the merge state is clean. Enabling auto-merge on the head above.

(Written by Claude Opus 5.5)

@kixelated
kixelated merged commit b52cf2c into main Oct 7, 2026
7 checks passed
@kixelated
kixelated deleted the quest/m0/broadcast-epoch/gst branch October 7, 2026 15:45
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