Skip to content

fix(net): write IETF data stream headers in one write - #6504

Merged
kixelated merged 3 commits into
mainfrom
quest/m1/interop-coverage/js-imquic-objects
Oct 23, 2026
Merged

kixelated merged 3 commits into
mainfrom
quest/m1/interop-coverage/js-imquic-objects

Conversation

@kixelated

@kixelated kixelated commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Works on quest/m1/interop-coverage/js-imquic-objects.md.

Cause

The runner's moq-dev-js data-subgroup-basic gets no objects from imquic (draft-22, WebTransport). imquic is at fault, reported as meetecho/imquic#43: imquic_moq_parse_message creates a data stream on its first chunk, but only allocates the stream's buffer once the SUBGROUP_HEADER has parsed. When the header arrives across more than one read, the parse returns "need more data", the bytes are dropped, and every later chunk is appended to a NULL buffer (a silent no-op). At FIN the relay surfaces an empty object with alias 0 and logs No track found for that subscription. FETCH_HEADER takes the same path. Still present on imquic main at ade3937.

@moq/net 0.4.4 writes the header one field per write(), and the @moq/web-transport polyfill sent them as separate STREAM frames. The Rust publisher buffers the header, which is why moq-dev-rs passes.

Change

Group.encode (SUBGROUP_HEADER) and FetchHeader.encode now write the stream type and header in one write, like the one-write control messages from moq-dev/moq#6255. The fetch path no longer writes its stream type separately. The bytes on the wire are unchanged. The quest is rewritten to what remains: rechecking the cell once imquic or the runner's client moves. The interop audit lists the imquic issue with the other upstream reports.

Consumer: every JS publisher talking moq-transport, here the runner's moq-dev-js client against imquic.

Public API: none (ietf/ wire types are internal). Wire: none.

Verification

Against the runner's ghcr.io/englishm/moq-interop-runner-imquic-moq-relay:latest locally and the registered https://lminiero.it:9000:

  • Runner client on published 0.4.4: fails every run with all 15 objects missing.
  • Same client, 0.4.4 patched so Group.encode writes once: passes 3/3 locally and against lminiero.it.
  • The case ported to main's API: passes 3/3 with this PR, fails 2/2 without it.

Decisions

  1. Post the imquic issue on meetecho/imquic?
    • ✅ Yes (maintainer, 2026-10-23). No existing report or fix in meetecho/imquic issues or PRs; filed as meetecho/imquic#43.
    • No.
  2. Keep this change, given the root cause is imquic's?
    • ✅ Keep (maintainer, 2026-10-23). It matches the Rust publisher and the control-message precedent, and it also covers FETCH_HEADER.
    • Drop it and wait on imquic.

Checks

  • just check: pass (after merging main).
  • bun test src/ietf in js/net: 803 pass.
  • just test interop --all: pass (164 cases, none failed or skipped).

Follow-ups

  • On main, request(path, { announced: true }) over moq-transport asks SUBSCRIBE_NAMESPACE for the exact path, and imquic never answers with the shorter routing prefix the publisher announced, so the runner case stalls before it subscribes. 0.4.4 asked for the scoped prefix. The runner client hits this when it moves past 0.4.4. Tracked in the quest's Remaining list.
  • js -> rust failed on drafts 14, 16, and 18 in just test interop --versions ietf on main locally before this change too (the JS publisher ends the catalog track with PUBLISH_DONE straight after SUBSCRIBE_OK). Check the nightly before planning.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits October 22, 2026 22:09
imquic parses a SUBGROUP_HEADER or FETCH_HEADER only from the first read
of a stream and drops the rest when the header arrives split. The JS
publisher wrote the header one field per write, so imquic received no
objects from @moq/net over WebTransport. Write each header, stream type
included, as one chunk, matching the Rust publisher and the one-write
control messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title JS subgroup data reaches the subscriber through imquic fix(net): write IETF data stream headers in one write Oct 23, 2026
@kixelated

Copy link
Copy Markdown
Collaborator Author

Outcome: cause found and reproduced. imquic drops a SUBGROUP_HEADER (and FETCH_HEADER) that arrives across more than one stream read, and @moq/net 0.4.4 wrote the header one field per write. This PR writes both headers in one write; the case passes against imquic with it and fails without it. Kept as a draft: posting the drafted imquic issue and keeping the change are maintainer decisions (see the body).

(Written by Claude Opus 5.5)

@kixelated kixelated mentioned this pull request Oct 23, 2026
# Conflicts:
#	quest/m1/interop-coverage/js-imquic-objects.md
#	quest/m1/interop-coverage/runner-cases.md
@kixelated
kixelated marked this pull request as ready for review October 23, 2026 16:48
@coderabbitai

coderabbitai Bot commented Oct 23, 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 15 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: 7bcbdbfb-53b0-4d2a-aa84-dccf5001a9d1
📥 Commits

Reviewing files that changed from the base of the PR and between 397e251 and 8e0a2de.

📒 Files selected for processing: 7
  • js/net/src/ietf/fetch.ts
  • js/net/src/ietf/object.test.ts
  • js/net/src/ietf/object.ts
  • js/net/src/ietf/publisher.ts
  • quest/m1/audit-interop.md
  • quest/m1/interop-coverage/README.md
  • quest/m1/interop-coverage/js-imquic-objects.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 23, 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-23T16:51:02.004161Z 8e0a2de Draft marked ready
ℹ️ 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

Copy link
Copy Markdown
Collaborator Author

Merging. The maintainer settled both decisions recorded in the description: the imquic issue is filed as meetecho/imquic#43, and the single-write header is kept. CI passed 11/11, Codex reacted 👍 on this head, and quest check passes against main.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit c3b2c1b Oct 23, 2026
11 checks passed
@kixelated
kixelated deleted the quest/m1/interop-coverage/js-imquic-objects branch October 23, 2026 18:03
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