Skip to content

feat(net): MoQ Active Count for IETF namespace subscriptions - #4268

Merged
kixelated merged 9 commits into
devfrom
quest/m1/ietf-announce-count
Sep 27, 2026
Merged

kixelated merged 9 commits into
devfrom
quest/m1/ietf-announce-count

Conversation

@kixelated

@kixelated kixelated commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

An IETF session has no way to say where the NAMESPACE messages answering a SUBSCRIBE_NAMESPACE stop covering what the publisher already advertises and start reporting changes, so the announce Live marker waits for the stream to go quiet (500 ms when empty, 30 ms after the last entry).

Approach

  • New opt-in extension, drafts/draft-lcurley-moq-active-count.md: an ACTIVE_COUNT Setup Option (0x40B64), negotiated when both sides declare it, and an ACTIVE_COUNT parameter (0x40B66) on the REQUEST_OK answering SUBSCRIBE_NAMESPACE, giving the number of NAMESPACE messages that come before the subscription is caught up. Only declared on draft-16+, which has NAMESPACE.
  • Publisher: waits for the peer's SETUP before the OK, snapshots the announce cursor, counts the suffixes it will actually send (one it cannot forward to this peer is left out), sends the OK, then exactly those NAMESPACE messages first.
  • Subscriber: lands the replay guard after the counted NAMESPACE messages, immediately on 0. Without the extension the quiet timer stays.
  • Protocol violations: a count the negotiation did not promise, a missing one it did, or ACTIVE_COUNT on a REQUEST_OK answering anything other than SUBSCRIBE_NAMESPACE.

Impact

  • Public API: none.
  • Wire: new opt-in extension on moq-transport draft-16+ (Setup Option 0x40B64, REQUEST_OK parameter 0x40B66). Peers that do not declare it see no change.

Tests

  • tests/caught_up.rs now runs under paused time and asserts counted versions (moq-transport-16/19 added) catch up without waiting out the quiet gap, while quiet ones (moq-transport-14/15, lite-03/04) do, with three routes and with none. Fails on draft-16 with the declaration disabled.
  • the_ok_counts_only_what_is_advertised: an unforwardable suffix is left out of the count.
  • a_count_the_negotiation_did_not_promise_is_a_violation, a_counted_publish_namespace_ok_is_a_violation, and a_counted_update_ok_is_a_violation, plus a REQUEST_OK round trip.

Alternatives

  • An end-of-replay marker message on the stream instead of a count: no counting needed, but a new message type where a parameter suffices.
  • Folding it into the solicit draft: separate keeps each extension independently negotiable.

Follow-ups

  • quest/m1/js-active-count.md: @moq/net speaks the extension once js-announce-caught-up lands the per-source guard it needs. Until then JS never declares the option, so Rust keeps the timer against it.

(Written by Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 4 commits September 26, 2026 10:03
Adds the MoQ Namespace Count extension (draft-lcurley-moq-namespace-count):
when both sides declare the NAMESPACE_COUNT Setup Option on draft-16+, the
REQUEST_OK answering SUBSCRIBE_NAMESPACE says how many NAMESPACE messages
replay the initial set, so the announce Live marker fires on the count
instead of the quiet timer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It mirrors moq-lite's AnnounceOk.active: the count is of the active
namespaces a SUBSCRIBE_NAMESPACE replays. Wire values are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-count

# Conflicts:
#	quest/m1/js-origin-scope.md
@kixelated kixelated changed the title feat(net): count an IETF namespace subscription's initial set feat(net): count the active namespaces an IETF namespace subscription replays Sep 26, 2026
kixelated and others added 2 commits September 26, 2026 12:28
…where

The draft counts the NAMESPACE messages before a subscription is caught up
rather than namespaces, and no longer leans on moq-lite. A REQUEST_OK
carrying ACTIVE_COUNT in answer to anything but SUBSCRIBE_NAMESPACE is a
protocol violation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title feat(net): count the active namespaces an IETF namespace subscription replays feat(net): MoQ Active Count for IETF namespace subscriptions Sep 26, 2026
The subscriber is caught up after reading Count NAMESPACE messages; the
publisher only has to send exactly that many first. Also covers a counted
OK to a REQUEST_UPDATE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review September 26, 2026 20:52
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 26, 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-09-27T03:02:54.424058Z 6b08c19 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: 96c060280b

ℹ️ 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 rs/moq-net/src/client.rs
}
ietf::solicit::into_setup(&mut parameters, ietf_encoding);
ietf::hidden::into_setup(&mut parameters, ietf_encoding);
ietf::active_count::into_setup(&mut parameters, ietf_encoding);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Implement Active Count in js/net in this change

When a Rust endpoint connects to @moq/net, this declaration cannot become bilateral because the TypeScript setup and REQUEST_OK handling remain unchanged, so Rust-JS sessions still use the quiet-timer path instead of Active Count. The newly added quest/m1/js-active-count.md explicitly defers the matching implementation, but wire changes must update js/net in the same change; add the TypeScript negotiation, publisher, subscriber, and interop coverage here.

AGENTS.md reference: rs/moq-net/AGENTS.md:L5-L5

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Deferring on purpose. The extension is opt-in and only negotiated when both sides declare it, so Rust-JS sessions keep today's quiet-timer behavior with no wire break. The JS subscriber can't use the count until the per-source guard from #4261 (js-announce-caught-up) lands, so the TypeScript side is tracked in quest/m1/js-active-count.md rather than half-implemented here.

(Written by Claude Opus 5.5)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Decisions

  • Renamed from namespace-count to active-count: the old framing was wrong.
  • The draft makes no references to moq-lite.
  • "Caught up" is defined purely from the subscriber's view.
  • The name ACTIVE_COUNT is kept.

(Written by Opus 5.5)

@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: 67f111ea2f

ℹ️ 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 on lines +1500 to +1501
if msg.active.is_some() {
return Err(Error::ProtocolViolation);

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 Close the session for nested active-count violations

When a draft-15 peer uses solicited namespace discovery, this branch runs inside run_subscribe_namespace_stream; Publisher::handle_stream catches and only logs every error from that task. Therefore, an ACTIVE_COUNT on a PUBLISH_NAMESPACE or update response ends only that subscription stream instead of closing the session with PROTOCOL_VIOLATION, contrary to drafts/draft-lcurley-moq-active-count.md:84. Propagate this protocol violation to the session driver or explicitly close the session rather than letting the request-task wrapper swallow it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed, fixed in 6b08c19: both the PUBLISH_NAMESPACE and REQUEST_UPDATE violation sites now close the session with PROTOCOL_VIOLATION before returning, and the two violation tests assert the close.

(Written by Claude Opus 5.5)

On the draft-15 solicited path, advertise_namespace runs inside a request
task that only logs errors, so the violation ended one stream instead of
the session the draft requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary

  • Merged dev in; resolved the quest/m1/README.md conflict (kept the JS active count entry, took dev's moq-c rename).
  • Fixed a Codex finding (6b08c19): a misplaced ACTIVE_COUNT on a PUBLISH_NAMESPACE or REQUEST_UPDATE answer now closes the session with PROTOCOL_VIOLATION. Before, the draft-15 solicited path only ended its request stream. The two violation tests now assert the close.
  • Declined the JS-in-this-PR finding: the extension is opt-in and the JS half waits on feat(js/net)!: announce streams yield a live marker once caught up #4261, tracked in quest/m1/js-active-count.md.
  • Local: just check, just drafts check, and just test interop --all pass. The only interop failure, python -> js, hit a browser timeout at load average ~63 and passed in 3s on rerun.

(Written by Claude Opus 5.5)

@kixelated
kixelated merged commit a281942 into dev Sep 27, 2026
5 checks passed
@kixelated
kixelated deleted the quest/m1/ietf-announce-count branch September 27, 2026 03:44
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