Repository navigation
fix(net): fill no history below a subscription's start that its reader skips - #7168
Conversation
…r skips A reader with the default oldest range asked a fill for every group below SUBSCRIBE_START. On an untimed copy each looked fresh, so lite-05 and moq-transport pulled the publisher's whole cached history on every first subscribe, and lite-07 sent one FETCH per stale group for the publisher to refuse. Below a start the publisher resolved from a budget no tighter than the reader's (lite-06+), every group is stale: the reader gives the run up unasked. Below a live edge start, it fills only a floor its ranges name. 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 17 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. Comment |
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. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 410a5d5
P2 — Do not attribute a START to the original budget after a pre-START update (rs/moq-net/src/lite/subscriber.rs:8013–8017). The publisher can apply SUBSCRIBE_UPDATE before selecting its first group: RequestServe retains updates while resolving the source, then TrackRun::update changes the cursor's max_delay. For example, SUBSCRIBE at 30s followed by a same-start update to 10s before START can produce a start resolved under 10s, but this code records 30s. A subsequent 20s reader then satisfies drift.budget <= start_budget in Misses::judge and permanently gives up potentially usable history below that start instead of requesting it. Checking only active.start == active.requested does not detect this. Conservatively invalidate the budget proof once an update could have changed the start calculation, or explicitly correlate START with the budget used by the publisher; add a delayed-START regression with tightening followed by partial widening.
Overall direction: suppressing unrequested history is useful, and keeping named-floor fills separate is sensible, but the new permanent-staleness inference needs a trustworthy budget. Verification: static inspection of the changed model, subscriber and publisher control flow and tests only; I did not run tests.
…low-ups (moq-dev#7179) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Problem
A fresh subscriber with the default
Range::oldestasked a fill for every group below SUBSCRIBE_START.Misses::judgegives up a run only when its newest group already looks stale, and an untimed copy judges by wall-clock arrival at its own hop, so the run looked fresh and went out as a FETCH. A reader then pulled the publisher's whole cached history on every first subscribe, direct or through a relay:max_delay2.5s, groups 0..9 one second apart)Bisected to moq-dev/moq#6171 (fills for misses).
Approach
In
Misses::judge:max_delayits SUBSCRIBE carried alongside the SUBSCRIBE_START it answered (Producer::start_resolved). A reader whose budget is no looser gives up every run below that start without asking, through the existing stale path, naming them dropped as lite-07 already did once the publisher refused them. A looser reader behaves as before: lite-06 waits for the re-offer (fix(net): close the relay demand gaps #7052), and lite-07 fills with a FETCH that carries itsmax_delay.Window::named). An absolute floor still fills (history_groups,late_lower_group), butRange::oldestno longer does. These groups are not stale, only unrequested, so they are skipped rather than dropped.Tests:
widened_max_age::a_fresh_reader_fills_nothing_below_its_startcovers lite-04/05/06/07 and moq-transport-18/22, direct and through a relay, and asserts that no lite FETCH goes out. It fails onmain.below_a_start_resolved_from_a_budget_only_a_looser_reader_askspins the budget comparison in the model.range_anchors::every_wire_carries_the_live_and_oldest_startsnow expects only the latest group fromoldeston lite-05 and moq-transport, andwarm_backfillnames floor0..so it still exercises the backfill path.Impact
Range::oldest(the default range) on moq-lite-05 and moq-transport: a subscription gets no history below the live edge unless it names a starting group, whatever itsmax_delay. An untimed copy cannot bound that history by the budget, so filling it pulled everything cached. To keep reading history there, name a starting group, such aswith_range(n..). Maintainer decision (2026-10-28): keep this.Range::oldest's doc anddoc/concept/moq-lite.mdsay so.Window::namedandProducer::start_resolvedare crate-internal.Alternatives
max_delay: lite-05/06 readers would lose history they ask for, and lite-07 would keep its refused FETCHes.Checks
just cion this head passes: check and test for rs (moq-net nextest 1243, workspace 9022 passed), js, markdown and gh.cargo nexteston moq-net, moq-net-tests, moq-relay, moq-bench, hang, moq-mux and moq-hls (all features): 5849 passed.An earlier note here blamed a
cargo fmt --all --checkfailure indemo/carla/bridgeon upstream. It was local: that checkout sat under a directory whoserustfmt.tomlsetshard_tabs, and rustfmt searches past the repository root.mainand this branch are clean.Follow-ups
main, a cold relay copy with an absolute floor0..serves only the latest group: the copy records start 0, but the publisher's cursor starts at the live edge. Hence its absence fromwarm_backfill.netmay have the same below-start over-fetch. This PR does not check it.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code