Skip to content

feat(net): negotiate IETF subscriber max age - #5993

Merged
kixelated merged 10 commits into
mainfrom
quest/m1/ietf-max-age
Oct 20, 2026
Merged

kixelated merged 10 commits into
mainfrom
quest/m1/ietf-max-age

Conversation

@kixelated

@kixelated kixelated commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

A moq-transport subscriber cannot bound the age of groups the publisher serves. IETF delivery timeouts also expire the newest group and cannot represent moq-lite's subscription budget.

Closes #5881.

Approach

Negotiate subscriber max age in SETUP, carry the existing max-delay budget on SUBSCRIBE and REQUEST_UPDATE, and apply it through the existing group-expiration policy in Rust and JavaScript. Relays retain the most tolerant subscriber's budget; absence preserves retained backlog, and the newest group survives every budget. Metadata query subscriptions follow the aggregate too, so an initial budget cannot mask a later decrease. Update the Timestamp draft and standard guidance.

Direct subscription fixtures now explicitly declare their peer SETUP. Delayed-SETUP tests and peers without max-age support retain their existing negotiation assertions.

Impact

  • Public API: none.
  • Wire, alongside MoQ Epoch: SUBSCRIBE may carry both EPOCH (0x40B69, draft 17+) and MAX_AGE (0x915C6); keys are encoded in ascending order.
  • Wire: additive MAX_AGE Setup Option 0x915C4 and subscriber parameter 0x915C6, in milliseconds, on drafts 14 through 22. Send the parameter only to peers declaring the option.
  • Delivery timeouts remain accepted and ignored.

Alternatives

Reusing OBJECT_DELIVERY_TIMEOUT or SUBGROUP_DELIVERY_TIMEOUT would cut newest groups, including quiet catalog snapshots. Sending an unnegotiated parameter would close legacy sessions.

Validation

Validated commit 7116ef3dfe8dce247c2d43e5a0f954e09cac9778:

  • just check: passed, including all 7,535 native tests, additional feature suites, workspace JavaScript tests and type checks, documentation, lint, and target checks.
  • just drafts check: passed.
  • just rs test -p moq-net: all 2,518 tests passed, 8 skipped. The initial broad run exposed two joining-FETCH fixtures that never supplied peer SETUP; explicit fixture declarations fix both without changing production negotiation.
  • just rs test -p moq-net -E 'test(subscriber_max_age) | test(ietf::subscribe::tests) | test(partial_group::)': all 49 tests passed, including most-tolerant aggregation and budget decreases across supported drafts, newest catalog survival, and partial-group resets.
  • 13 targeted JavaScript regressions passed. The original publisher fails a requested 250ms budget as unlimited. The active-reader relay regression fails without the query-hold update: the publisher stays at 250ms instead of the requested 10ms after a tolerant subscriber leaves.
  • just test interop --publishers rust,python,go,cpp --subscribers rust,python,go,cpp,js-native-node,js-native-bun,c,gst --timeout 30: passed all available native matrix, unauthorized-publisher, CLI FETCH, and finite-tail checks.
  • just test drill ietf_subscriber_max_age_skips_bufferbloat: passed. The drill uses a finite 500ms queue below the media bitrate and verifies overflow drops, with random loss disabled.
  • just test drill-sensitivity --no-baseline subscriber-max-age-ignored: passed, 1 of 1. Removing initial publisher max-age application makes the drill fail with subscriber max age did not reach the publisher. Patch application also passed separately.

Iteration (Claude Opus 5.5)

Merged origin/main (MoQ Epoch, #5836 and neighbors). Conflicts were unions of the two extensions' fields in Peer, PeerSetup, Subscribe, the SETUP parameter enum, and the JS subscriber. The Rust parameter macros require ascending keys, so EPOCH now precedes MAX_AGE in SUBSCRIBE encode and decode. No review findings were posted.

Decisions: none needed; the merge adopted main's PeerSetup::new and kept this PR's PeerSetup::declared test fixture.

Validated on the merge commit:

  • just check: passed.
  • just drafts check: passed.
  • just rs test -p moq-net (nextest, all features): 2,572 passed, 8 skipped.
  • js/net typecheck and bun test src/ietf: 701 passed.
  • just test interop --all, browser included: all checks passed. This closes the gate the previous iteration left open.

Round 2 (Claude Opus 5.5)

Codex finding r4320231271: JS draft-17+ dial and accept dropped maxAge when destructuring the SETUP result, so JS never sent MAX_AGE on ALPN-selected drafts. Both call sites now spread the whole result. A new js/net/src/integration.test.ts case covers drafts 16, 17, and 22 end to end; 17 and 22 fail without the fix. just check and just test interop --all pass on the fix.

Merged origin/main again (refresh-ratio dynamic groups): SUBSCRIBE and REQUEST_UPDATE keep the max age alongside main's fixed-range bounds and join-judged NEW_GROUP_REQUEST, and the subscriber-max-age-ignored drill mutation is retargeted (the drill passes at baseline and fails with the mutation). just check and moq-net and js/net tests pass on the merge; just test interop --all was rerun on the final head.

Follow-ups

None.

🤖 Generated with Claude Code

(Written by GPT-6.1-Sol; iterated by Claude Opus 5.5)

kixelated and others added 6 commits October 19, 2026 12:54
Map negotiated SUBSCRIBE and REQUEST_UPDATE budgets onto existing subscription max delay in Rust and JavaScript. Preserve legacy backlog behavior and newest groups, and relay the most tolerant subscriber budget.

Checkpoint: JS max-age regressions and net typecheck pass. Rust integration helper compile fix, draft parsing, full checks, cross-language interop, and shaped acceptance validation remain pending.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Mirror the accepted track aggregate into its metadata query subscription so the original max-delay budget cannot mask a later decrease. Drive the regression reader while updating its preferences, as required by the caller-driven route cursor.

Validation: all 49 scoped IETF codec, two-hop max-age aggregation, catalog survival, and partial-group regressions pass. The active-reader regression fails without the query-hold fix.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Validation: full branch check caught the incorrect draft URL; generated site route is /draft/moq-timestamp.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Direct full-subscription fixtures now model a received SETUP without extensions, so capability negotiation can complete. Leave delayed-SETUP and raw receiver fixtures unchanged.

Validation: all 2518 moq-net tests pass, including two-hop max-age aggregation and the legacy joining-fetch cases.

Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
Resolve conflicts with MoQ Epoch: SUBSCRIBE carries both parameters, encoded in ascending key order (EPOCH 0x40B69 before MAX_AGE 0x915C6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review October 20, 2026 00:20
@coderabbitai

coderabbitai Bot commented Oct 20, 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 11 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: 88411873-36a4-44dc-a33e-5a9192088b35
📥 Commits

Reviewing files that changed from the base of the PR and between 3b77d23 and b684e8d.

📒 Files selected for processing: 37
  • doc/concept/standard.md
  • drafts/draft-lcurley-moq-timestamp.md
  • js/net/src/connection/accept.ts
  • js/net/src/connection/connect.ts
  • js/net/src/connection/handshake.ts
  • js/net/src/ietf/connection.ts
  • js/net/src/ietf/index.ts
  • js/net/src/ietf/max-age.test.ts
  • js/net/src/ietf/max_age.ts
  • js/net/src/ietf/parameters.ts
  • js/net/src/ietf/publisher.test.ts
  • js/net/src/ietf/publisher.ts
  • js/net/src/ietf/subscribe.ts
  • js/net/src/ietf/subscriber.test.ts
  • js/net/src/ietf/subscriber.ts
  • js/net/src/integration.test.ts
  • rs/moq-net/src/client.rs
  • rs/moq-net/src/fuzz.rs
  • rs/moq-net/src/ietf/adapter.rs
  • rs/moq-net/src/ietf/max_age.rs
  • rs/moq-net/src/ietf/mod.rs
  • rs/moq-net/src/ietf/parameters.rs
  • rs/moq-net/src/ietf/peer.rs
  • rs/moq-net/src/ietf/publisher.rs
  • rs/moq-net/src/ietf/request_stream.rs
  • rs/moq-net/src/ietf/session.rs
  • rs/moq-net/src/ietf/subscribe.rs
  • rs/moq-net/src/ietf/subscriber.rs
  • rs/moq-net/src/ietf/version.rs
  • rs/moq-net/src/model/origin.rs
  • rs/moq-net/src/server.rs
  • rs/moq-net/tests/integration/main.rs
  • rs/moq-net/tests/integration/partial_group.rs
  • rs/moq-net/tests/integration/subscriber_max_age.rs
  • rs/moq-relay/tests/drills.rs
  • test/drill/README.md
  • test/drill/mutations/subscriber-max-age-ignored.patch
  • Autofix · 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.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 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-10-20T02:07:34.421165Z b684e8d New commits
ℹ️ 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: 9b506f9259

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

Comment thread js/net/src/connection/handshake.ts
kixelated and others added 4 commits October 19, 2026 18:30
Draft-17+ dial and accept destructured the SETUP result field by field and dropped maxAge, so JS subscribers never sent MAX_AGE on ALPN-selected drafts. Spread the whole result so every negotiated flag reaches the connection. An end-to-end JS test now checks SUBSCRIBE and REQUEST_UPDATE budgets reach the publisher on drafts 16, 17, and 22; 17 and 22 fail without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve conflicts with the dynamic-groups refresh ratio: SUBSCRIBE and REQUEST_UPDATE keep the subscriber max age alongside main's fixed-range bounds and join-judged NEW_GROUP_REQUEST.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Validation: the drill passes at baseline and fails with the mutation applied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated added this pull request to the merge queue Oct 20, 2026
Merged via the queue into main with commit 559b362 Oct 20, 2026
16 checks passed
@kixelated
kixelated deleted the quest/m1/ietf-max-age branch October 20, 2026 03:11
kixelated added a commit that referenced this pull request Oct 20, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

IETF subscribers cannot bound delivery lateness: SUBSCRIBE delivery timeouts are dropped and no max_delay maps from the wire

1 participant