Skip to content

fix(js): never hold overlapping SUBSCRIBE_NAMESPACEs at a foreign peer - #6714

Merged
kixelated merged 5 commits into
mainfrom
quest/m1/ietf-lazy-discovery
Oct 25, 2026
Merged

kixelated merged 5 commits into
mainfrom
quest/m1/ietf-lazy-discovery

Conversation

@kixelated

@kixelated kixelated commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Finishes quest/m1/ietf-lazy-discovery.md: a JS moq-transport session never holds two overlapping SUBSCRIBE_NAMESPACE requests at a peer that declared no MoQ Solicit. A peer that enforces PREFIX_OVERLAP (such as moxygen) no longer refuses a broader watch and turns the session blind. This mirrors the Rust side from moq-dev/moq#6530.

Changes

  • connection/forward.ts: at such a peer, discovery is exclusive. A broader request closes every narrower request beneath it, watched or lingering. Our own peers keep the overlapping hold semantics.
  • ietf/subscriber.ts: a request goes out only after every overlapping request already closed has left the wire. On drafts 14/15 that means the UNSUBSCRIBE_NAMESPACE is written, since requests share the ordered control stream. From draft 16 it means the peer has ended its half: we FIN where FIN cancels (drafts 16-18) or reset with CANCELLED (draft 19+), drop whatever the peer still sends, and wait for its end. This replaces the immediate FIN plus STOP_SENDING, which gave no signal. A request's routes go as soon as it starts ending.
  • ietf/request_stream.ts: RequestStream.cancel() cancels a request but keeps reading.
  • A closed reader stays registered while its request drains, so attach, settle, and detach now all skip closed readers. Before, attach would throw into another request's read loop.
  • The internal wire.Established view gains exclusive: ietf sets it to solicit === undefined, lite sets it to false.

Choices made

  • Like Rust, a request waits only on overlapping requests that are already closing, on every session. At our own peers this adds one RTT only when an overlapping request reopens right after one closes.
  • A replaced narrower request's routes end, then return once the broader request reports them, as in Rust. Keeping them would join two publisher instances with nothing to prove they are the same one.
  • Like Rust, a peer that never ends its half after our cancel blocks an overlapping request until the session ends. Our JS and Rust publishers both end their half.

Impact

  • Public API: none.
  • Wire: none. Draft 16+ cancels now keep reading until the peer's end instead of sending STOP_SENDING.

Checks

  • just check passes (JS check and tests, markdown, quest, shell).
  • New tests: exclusive forwarding in forward.test.ts; a draft-19 overlap that waits on the peer's half, and draft-15 ordering behind UNSUBSCRIBE_NAMESPACE, in subscriber.test.ts. The draft-19 test fails without the change.
  • Not run: just test interop --all, since no wire format changed.

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

kixelated and others added 2 commits October 24, 2026 22:39
A peer that declared no MoQ Solicit may enforce the drafts' PREFIX_OVERLAP
rule, as moxygen does, and refuse a broader watch held beside a narrower
one, which turned the JS session blind. Mirror Rust (#6530):

- forward.ts runs exclusive discovery at such a peer: a broader request
  closes the narrower ones beneath it, watched or lingering.
- The ietf subscriber holds a request until every overlapping request
  already closed is off the wire: UNSUBSCRIBE_NAMESPACE written on drafts
  14/15, the peer's half ended from draft 16 (FIN or CANCELLED reset, then
  drain).
- A closed reader stays registered while its request drains, so no
  announcement is appended to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title IETF lazy discovery in JS fix(js): never hold overlapping SUBSCRIBE_NAMESPACEs at a foreign peer Oct 25, 2026
@kixelated
kixelated marked this pull request as ready for review October 25, 2026 05:55
@coderabbitai

coderabbitai Bot commented Oct 25, 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 21 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
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4c6b3505-b93f-4316-9d5e-6c943b840c92
Commits

Reviewing files that changed from the base of the PR and between 3fc5799 and 96d9a58.

Files selected for processing: 13
  • doc/concept/standard.md
  • js/net/bench/forward.ts
  • js/net/src/connection/forward.test.ts
  • js/net/src/connection/forward.ts
  • js/net/src/ietf/connection.ts
  • js/net/src/ietf/request_stream.ts
  • js/net/src/ietf/subscriber.test.ts
  • js/net/src/ietf/subscriber.ts
  • js/net/src/lite/connection.ts
  • js/net/src/wire.ts
  • quest/m1/README.md
  • quest/m1/ietf-lazy-discovery.md
  • quest/m1/ietf-request-cancel.md
  • 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 25, 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-25T17:18:52.677469Z 96d9a58 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.

@kixelated kixelated left a comment

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.

Automated review by review (OpenAI)

Reviewed commit: c1da613

No actionable bugs found. Separating local watcher closure from confirmed wire teardown is the right direction: broader discovery closes narrower interests, and overlapping replacements wait for ordered UNSUBSCRIBE_NAMESPACE on drafts 14/15 or the peer's stream end from draft 16 onward. Keeping closed readers registered only for that barrier, while excluding them from announcement delivery, avoids reviving closed consumers. Explicit route withdrawal during replacement is consistent with not assuming publisher identity.

Verification: static inspection of forwarding, subscriber teardown and RequestStream ownership, plus new exclusive-forwarding and draft-15/19 tests. I did not run tests or cross-implementation interop; the draft-16–18 FIN-cancellation path was inspected, not exercised.

@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: c1da6139fc

ℹ️ 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/ietf/subscriber.test.ts Outdated
kixelated and others added 3 commits October 25, 2026 10:09
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	doc/concept/standard.md
Drafts 19-21 were dropped on main, and VERSION is now draft 18, whose FIN
cancels, so the test pins draft 22 and the helpers take its version.

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

@kixelated kixelated left a comment

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.

Automated review by review (OpenAI)

Reviewed commit: 96d9a58

Compared with c1da613, accounting for main integration. The independent wall-clock assertion finding #6714 (comment) is addressed: the absence assertion now observes a pending stream read after confirmed session progress, then awaits that same read after peer closure. Moving this reset-cancellation case to supported draft22 preserves its purpose after drafts19–21 were removed.

No new actionable bugs found. The focused test changes strengthen verification without changing the reviewed overlap-barrier design.

Verification: static inspection of both test-fix commits and surrounding subscriber, forwarding and cancellation paths. No tests or interop runs performed.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merged main. Changes since the last review:

  • The draft-19 overlap test no longer waits 500 ms of wall clock: it holds a pending read of the next incoming stream, asserts it is still pending once the session has visibly made progress, and awaits that read after the peer ends its half (addresses the Codex thread).
  • moq-dev/moq#6754 dropped drafts 19-21 and moved the suite's default to draft 18, whose FIN cancels, so that test now pins draft 22 (reset cancels) and the stream helpers take a version. It still fails against main's subscriber.ts.
  • doc/concept/standard.md conflict: kept main's draft renumbering with this PR's "We never hold two overlapping requests" wording.

just check (js, markdown, gh, quest, shell) and quest check --base origin/main pass; Codex and the OpenAI review cover this head. Landing.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit a7e72ae Oct 25, 2026
11 checks passed
@kixelated
kixelated deleted the quest/m1/ietf-lazy-discovery branch October 25, 2026 19:54
kixelated added a commit that referenced this pull request Oct 25, 2026
The adapter's lost-AUTH change (#6734) goes with the adapter; its session
tests move to draft 18. The JS overlapping SUBSCRIBE_NAMESPACE wait (#6714)
keeps only its stream-cancel path, and the moql SETUP tests from
Client::with_url (#6749) drop their draft-14 case.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant