Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…est/m1/archive/dvr
|
Maintainer confirmed the API shape: keep (Written by Claude Opus 5.5) |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1ae6386fb
ℹ️ 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".
| let timescale = Timescale::new(scale).map_err(|_| Error::Timescale(scale))?; | ||
| let at = at.convert(timescale).map_err(|_| Error::Overflow)?.value(); | ||
|
|
||
| let subscriber = self.archive.track(&self.timeline.track)?.subscribe(None).await?; |
There was a problem hiding this comment.
Load the complete retained timeline before seeking
For any archive or DVR retaining more than moq_mux::timeline::CHECKPOINT_RECORDS (256) records, this default subscription can start at the latest timeline group. Its checkpoint contains only the newest 256 records and emits Skip for the older indices; because Archive::apply ignores Skip, seeking to an older timestamp silently starts at the oldest checkpoint record rather than the actual retained segment. Reconstruct the complete retained timeline, or explicitly reject timestamps outside the available checkpoint.
Useful? React with 👍 / 👎.
|
|
||
| fn apply(&mut self, event: moq_json::Result<Option<window::Event<Record>>>) -> Result<()> { | ||
| match event.map_err(|err| Error::Timeline(err.to_string()))? { | ||
| Some(window::Event::Push { index, value }) => self.index.push(index, &value), |
There was a problem hiding this comment.
Index only the track being rewound
Each seek creates an Archive for one requested track, but every timeline push indexes and clones the spans for every track in the record even though subsequent lookups use only self.name. With many simultaneous viewers, recorded tracks, and retained segments, this makes rewind state grow as viewers × tracks × segments instead of viewers × segments; filter ingestion to the requested track and benchmark both fan-out axes.
AGENTS.md reference: AGENTS.md:L35-L35
Useful? React with 👍 / 👎.
Problem
The archive line records a broadcast (
Writer) and serves it back (Reader), but nothing lets a viewer seek into a bounded recording and come back to live. Questquest/m1/archive/dvr.md.Approach
moq_archive::Rewindpairs a live broadcast with the replay broadcast aReaderserves.Rewind::seek(track, at)reads the replay's timeline, starts at the first group of the newest retained segment starting at or beforeat(the oldest one whenatpredates the window), and FETCHes each advertised group in order through the normalfetch_groupmiss chain.Subscription::startplus the localset_groups), so the splice reaches back into the live cache instead of jumping to the newest group. The recording keeps source sequences, so nothing repeats or rewinds.NotFoundis an ordinary gap.Indexmoved to the crate root and gainednextandseeklookups.Writer+Reader+ live source: seek within the window, seek before it, expiry mid-seek, missing groups (never produced and lost objects), a writer restart spanned by one seek, a track the recording never names, and the splice. A writer test proves an unbounded restart continues a DVR's segment numbering without rewriting any retained object. Mutating the splice floor or the gap handling fails the matching test.Group eviction in
moq-net: not neededA served group that later expires stays in the replay track's
moq_netcache until the pool reclaims it. No API is added:Rewindconsults the timeline before every FETCH, so it never asks for an expired group (the expiry test passes even withNotFoundhandling disabled, proving the pop path alone skips them). A direct FETCH of such a group can still hit the cache, which is harmless because its bytes are immutable and the writer never reuses a sequence. Recorded in the line README.Impact
moq-archive(0.0.x):rewindmodule,Rewind { new, seek },rewind::Track { is_live, poll_next_group, next_group }, re-exported asmoq_archive::Rewind.Alternatives
moq_nettracks: rejected above.Follow-ups
Rewindinto a player:moqCLI playback ormoq-ffi, then the browser once JavaScript FETCH and the browser archive land.just checkfails_publish-teston this line already:moq-cli'smoq-jsondev-dependency (from feat(cli): record and replay archives withexport archive/import archive#4113) should usepath = "../moq-json".Closes #2275
(Written by Claude Opus 5.5)
🤖 Generated with Claude Code