Skip to content

fix(net): bound reach by the immediate successor, and collapse snapshots mid-roll - #3167

Merged
kixelated merged 2 commits into
devfrom
claude/net-reach-followups
Aug 29, 2026
Merged

fix(net): bound reach by the immediate successor, and collapse snapshots mid-roll#3167
kixelated merged 2 commits into
devfrom
claude/net-reach-followups

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Follow-ups from the post-merge review round of #3099 (these fixes were verified locally but not yet pushed when that PR merged).

Fixes

  • Reach is bounded by the immediate servable successor only. It previously resolved to the next stamped group, so an unstamped immediate successor let a later group's timestamp stand in for it. Timestamps need not rise with sequence, so that shrank the bound in the unsafe direction: a rewind could expire a group whose content was still inside the budget. An unstamped successor now leaves the reach unbounded until it presents its first frame, in Rust (TrackState::reach, replacing the per-poll suffix table) and JS (Subscriber.#reach). A held group's expiry also registers on every unstamped servable group above it, so the verdict re-evaluates when the immediate successor gains its first timestamp.
  • The JS snapshot consumer collapses across a roll, not just on acquire. A consumer holding a group with buffered deltas replayed superseded state when the producer rolled a newer snapshot group; next() now abandons the held group whenever a newer one exists, mirroring the Rust consumer's drain-to-newest poll.
  • Draft consistency (draft-lcurley-moq-lite): the Expiration summary said age must exceed Max Age where the reach rule is an exclusive bound (>=), and the SUBSCRIBE section still told publishers to resolve Group Start from a group's first frame. Both now defer to the Expiration rule, keeping the promise that start selection and expiry cannot disagree.
  • Ordered.readFrame doc: no longer claims it discards older groups; it rides the sequence cursor and drains the backlog like every other ordered read.

Regression tests

  • an_unstamped_immediate_successor_leaves_reach_unbounded (rs) / an unstamped immediate successor leaves reach unbounded (js)
  • a held group is abandoned when a newer snapshot group rolls (js/json)

Test plan

  • cargo nextest run -p moq-net: 1014 passed. bun test in js/net and js/json: green. just drafts check passes. The full just check / just test sweep is running; CI on this PR is the gate either way.

(Written by Claude Fable 5)

…ots mid-roll

Follow-ups from the post-merge review of #3099. Reach resolved to the next
*stamped* group, so an unstamped immediate successor let a later group's
timestamp shrink the bound in the unsafe direction: a rewind could expire
content that was still inside the budget. Reach is now unbounded until the
immediate servable successor presents its first frame, in Rust and JS, and a
held group's expiry re-evaluates when that successor gains its timestamp.

The JS snapshot consumer only collapsed to the newest group when acquiring
one, so a held group's buffered deltas replayed superseded state across a
roll; it now abandons the held group whenever a newer one exists, mirroring
the Rust consumer.

The draft's Expiration summary said "exceeds" where the rule is an exclusive
bound, and SUBSCRIBE still resolved starts from a group's first frame; both
now defer to the reach rule so start selection and expiry cannot disagree.
Ordered.readFrame's doc no longer claims it discards older groups.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 29, 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-08-29T04:34:14.272165Z d8dcea0 PR opened
ℹ️ 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: d8dcea0e71

ℹ️ 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".

## Expiration
Expiration governs when an older group is dropped.
The publisher SHOULD reset Group Streams for non-latest groups whose age relative to the latest group exceeds `Subscriber Max Age` (see [SUBSCRIBE](#subscribe)); the subscriber MAY also locally drop such groups.
The publisher SHOULD reset Group Streams for non-latest groups whose age relative to the latest group reaches `Subscriber Max Age` (see [SUBSCRIBE](#subscribe), and the age definition below); the subscriber MAY also locally drop such groups.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the inclusive expiration threshold throughout the draft

This now specifies expiration when age reaches Subscriber Max Age, but the Subscriber Max Age field definition still says a publisher resets groups only when their age exceeds the duration (draft-lcurley-moq-lite.md:969-972). At exact equality, including the important zero-budget case, implementations following the field definition can retain a group that the normative Expiration section and both implementations consider expired. Update the field definition to use the same inclusive threshold.

Useful? React with 👍 / 👎.

The json-cut tests (#3146) and the ordered-handle rework (#3099) merged past
each other with cancelled CI, so dev's cut tests still call the pre-handle
structure(track.subscribe(...)) shape, which no longer typechecks or runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kixelated
kixelated merged commit 7a0b317 into dev Aug 29, 2026
3 checks passed
@kixelated
kixelated deleted the claude/net-reach-followups branch August 29, 2026 14:28
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