From d570589348438ac702a8ba24f9bc1354fbe2badf Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 10 Oct 2026 05:28:48 -0700 Subject: [PATCH 1/4] quest: plan the follower gap that #5154's review found Co-Authored-By: Claude Opus 5.5 --- quest/m0/broadcast-epoch/README.md | 1 + quest/m0/broadcast-epoch/follow-gap.md | 31 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 quest/m0/broadcast-epoch/follow-gap.md diff --git a/quest/m0/broadcast-epoch/README.md b/quest/m0/broadcast-epoch/README.md index 5e401842cf..4673a8a838 100644 --- a/quest/m0/broadcast-epoch/README.md +++ b/quest/m0/broadcast-epoch/README.md @@ -102,4 +102,5 @@ then. MoQ Pro's VOD `storage.json` moves from the same seed to its own epoch. - [Publish catalog restart](/quest/m0/broadcast-epoch/publish-catalog-restart.md) - `@moq/publish` never reuses catalog group numbers under one name and epoch after a re-announce - [Bindings](/quest/m0/broadcast-epoch/bindings.md) - moq-ffi and every wrapper expose the epoch and let a publisher announce one - [moqsrc](/quest/m0/broadcast-epoch/moqsrc.md) - moqsrc switches to the new broadcast on a `Restart`, keeping its pads by rendition name +- [Follow gap](/quest/m0/broadcast-epoch/follow-gap.md) - a followed path reports a gap that ended its request, even onto a same-epoch covering prefix - [Stats totals and prefix tracks](/quest/m0/broadcast-epoch/stats-split.md) - the same release retires the per-path stats maps for totals and on-demand prefix tracks (decided 2026-10-05) diff --git a/quest/m0/broadcast-epoch/follow-gap.md b/quest/m0/broadcast-epoch/follow-gap.md new file mode 100644 index 0000000000..9000e33c6c --- /dev/null +++ b/quest/m0/broadcast-epoch/follow-gap.md @@ -0,0 +1,31 @@ +# [S] A followed path reports a gap that ended its request + +## Goal + +`origin::Consumer::follow` reports a gap that ended the request (an `End` +then `Start`, or a `Restart`) even when the next serving route is a covering +prefix with the same epoch, so `moq play` never misses a handoff while it is +still draining the old run. + +## Plan + +Found by the OpenAI review of #5154 (2026-10-10), which added `follow` in +moq-net and `@moq/net`. A same-epoch handoff from the exact route to a +covering prefix, after a gap that ended the old request, reaches the Rust +follower as an `Update`, because the announce cursor delivers by prefix and +the follower never sees the gap. If that `Update` arrives while `moq play` is +draining the old run, playback never restarts. JS sees the gap and is +correct. + +Decided 2026-10-10: merge #5154 and fix the cause in moq-net here, in m0 +because the epoch line gates the release. Rejected: re-requesting in +`moq play` whenever a run fails while the path is still served, which loops +tightly on a broadcast that fails every time. + +Fix it in the announce cursor or the follower so the gap surfaces, matching +JS. Regression with simulated time: an exact route ends, its request ends, +then a same-epoch prefix route takes over while a reader is still draining; +the follower must report the handoff, and `moq play` must restart. Start +after #5154 merges. + +Public API: none expected. Wire: none. From 323babef4aa746f8bcd35087017002a83d837c69 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 10 Oct 2026 05:38:47 -0700 Subject: [PATCH 2/4] quest: note follow's behavior change in the API impact Co-Authored-By: Claude Opus 5.5 --- quest/m0/broadcast-epoch/follow-gap.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quest/m0/broadcast-epoch/follow-gap.md b/quest/m0/broadcast-epoch/follow-gap.md index 9000e33c6c..5e663654ab 100644 --- a/quest/m0/broadcast-epoch/follow-gap.md +++ b/quest/m0/broadcast-epoch/follow-gap.md @@ -28,4 +28,5 @@ then a same-epoch prefix route takes over while a reader is still draining; the follower must report the handoff, and `moq play` must restart. Start after #5154 merges. -Public API: none expected. Wire: none. +Public API: no new items, but `follow` reports a gap where it reported an +`Update`, a behavior change to call out in the PR. Wire: none. From 0d111de6495b7c2d08e9145ac7abc8b2f6d447d6 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 10 Oct 2026 05:44:53 -0700 Subject: [PATCH 3/4] quest: keep the follow-gap regression from passing on broken code Co-Authored-By: Claude Opus 5.5 --- quest/m0/broadcast-epoch/follow-gap.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quest/m0/broadcast-epoch/follow-gap.md b/quest/m0/broadcast-epoch/follow-gap.md index 5e663654ab..490306ace5 100644 --- a/quest/m0/broadcast-epoch/follow-gap.md +++ b/quest/m0/broadcast-epoch/follow-gap.md @@ -25,8 +25,10 @@ tightly on a broadcast that fails every time. Fix it in the announce cursor or the follower so the gap surfaces, matching JS. Regression with simulated time: an exact route ends, its request ends, then a same-epoch prefix route takes over while a reader is still draining; -the follower must report the handoff, and `moq play` must restart. Start -after #5154 merges. +the follower must report the handoff, and `moq play` must restart. Leave the +follower unpolled until the replacement is announced, since awaiting its +`End` first avoids the bug and passes on the broken code. Start after #5154 +merges. Public API: no new items, but `follow` reports a gap where it reported an `Update`, a behavior change to call out in the PR. Wire: none. From 956660382f05f76b5f3da4f89b767752e09ce661 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Sat, 10 Oct 2026 05:52:40 -0700 Subject: [PATCH 4/4] quest: follow-gap is unblocked now that #5154 landed Co-Authored-By: Claude Opus 5.5 --- quest/m0/broadcast-epoch/follow-gap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quest/m0/broadcast-epoch/follow-gap.md b/quest/m0/broadcast-epoch/follow-gap.md index 490306ace5..638676535c 100644 --- a/quest/m0/broadcast-epoch/follow-gap.md +++ b/quest/m0/broadcast-epoch/follow-gap.md @@ -27,8 +27,8 @@ JS. Regression with simulated time: an exact route ends, its request ends, then a same-epoch prefix route takes over while a reader is still draining; the follower must report the handoff, and `moq play` must restart. Leave the follower unpolled until the replacement is announced, since awaiting its -`End` first avoids the bug and passes on the broken code. Start after #5154 -merges. +`End` first avoids the bug and passes on the broken code, as +`follow_keeps_a_gap_between_routes_of_one_epoch` does today. Public API: no new items, but `follow` reports a gap where it reported an `Update`, a behavior change to call out in the PR. Wire: none.