feat(moq-net,js/net): moq-lite-06-wip announce ids (typed START/END/RESTART, opt-in)#2160
Merged
Merged
Conversation
Each active ANNOUNCE_BROADCAST implicitly assigns the next per-stream ordinal; ended and restart reference that id instead of repeating the broadcast path. Restarts get their own explicit status instead of the duplicate-active idiom, and an unknown or retired id is a protocol violation. Announces that were filtered (loops, exclude_hop) never assign an id, so their retraction sends nothing. Negotiated via the new moq-lite-06-wip ALPN (wire code 0xff0dad06), preferred by default like previous wip drafts on dev. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mirror of the Rust change: AnnounceBroadcast becomes a discriminated union (active / ended / endedId / restart), the publisher assigns and retracts by ordinal on lite-06, and the subscriber resolves ids back to paths (an unknown or retired id is a protocol violation). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @kixelated, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
…cement-compression-0cc276 # Conflicts: # js/net/src/lite/announce.ts
Mirror the spec change into the in-repo drafts/ (moved here by #2159): each active ANNOUNCE_BROADCAST implicitly assigns the next per-stream ordinal, and ended/restart reference that id instead of repeating the broadcast path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The wire ALPN is now `moq-lite-06` (no `-wip` suffix); the internal `Lite06Wip` / `DRAFT_06` markers stay as the code-level not-finalized signal. Finalizing lite-06 becomes a pure rename (Lite06Wip -> Lite06) with no wire or config-string change, unlike lite-05 which had to rename its ALPN on the wire when it left WIP. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…TART/END/RESTART On lite-06 the announce stream now carries three independently-typed messages instead of one ANNOUNCE_BROADCAST with a status-dependent body, matching SUBSCRIBE_START/END/DROP: each is framed as an outer Type discriminator (START=0, END=1, RESTART=2) before the length prefix, so messages are length-delimited and skippable. lite-05 and older keep their frozen inner-status framing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…06-wip The lite-06 ALPN is 'moq-lite-06-wip' again, but it is no longer in the advertised sets: removed from moq_net::ALPNS and Versions::all(), and from the JS default protocols list. lite-06 is never negotiated by default; a peer only reaches it when both sides explicitly opt in (e.g. --version moq-lite-06-wip). The version stays fully defined so opt-in negotiates normally. The moq-native raw-QUIC accept path (noq/quinn/quiche) recognized ALPNs via the global moq_net::ALPNS const, which would reject an opt-in ALPN that isn't in the default set. Recognize the server's own configured ALPNs instead (rustls only negotiates an ALPN the server offered). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Satisfies clippy::manual_contains (rust 1.96, -D warnings in just ci). quiche's negotiated ALPN is a &str so contains() typechecks; quinn/noq hold it as a String and keep iter().any(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kixelated
added a commit
that referenced
this pull request
Jul 12, 2026
Reconcile the API-hardening PR with overlapping work that landed on dev. Where dev and this branch reshaped the same surface, resolved as follows: - read_frame / poll_read_frame (group + track): keep this branch's `frame::Frame` return; drop dev #2174's additive `read_frame_full` / `poll_read_frame_full` split. Redirected the moq-ffi / libmoq / internal callers to the collapsed `read_frame`; kept dev's MoqFrame + timestamp_us FFI plumbing (sourced from the Frame). - Subscriber::update / SubscriberControl::update: keep this branch's `Result` de-panic (dev's #2177 control() still panicked on a closed track); ignore the Result at the FFI/libmoq call sites where a closed-track update is meaningless. - moq_net::Subscription -> moq_net::track::Subscription in dev's newer libmoq. - OriginAnnounce tuple -> announce::Update struct in dev's moq-native lite-06 announce test. - js subscribe options: keep this branch's `Subscription` type name (mirrors Rust track::Subscription) over dev #2167's SubscribeOptions; keep the hooks indirection that hides the detached Request constructor. - lite/subscriber.ts: take dev's announce-id machinery (#2160, incl. AnnouncedOptions/ignoreSelf) wholesale; port its priority poll onto this branch's subscriptionSignal. Validated: cargo check/clippy --workspace clean; moq-net/moq-ffi/libmoq/ moq-native/moq-mux tests pass; js/net tsc+biome+236 tests; py 45 tests pass.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks broadcast announcements for moq-lite-06 so retracting or restarting an announcement no longer repeats the broadcast path.
The announce stream now carries three independently-typed messages, mirroring the subscribe stream's
SUBSCRIBE_START/END/DROP: each is framed as an outerTypediscriminator before the length prefix, so messages are length-delimited and skippable.0x0): a broadcast is available; carries the path suffix + hop chain, and implicitly assigns the next per-stream Announce ID (a 0-based ordinal, derived from message order, zero bytes on the wire).0x1): a broadcast is gone; carries only the Announce ID (~3 bytes total instead ofpath + hops), and retires it.0x2): atomically replace an advertisement; carries the Announce ID + the new hop list; the id stays live. This replaces the lite-05 duplicate-activeidiom. A secondANNOUNCE_STARTfor an already-available path is now a protocol violation.Referencing an unknown or retired id is a protocol violation; ids are never reused within a stream. Announcements filtered by loop detection or
exclude_hopnever get an id, so their retraction sends nothing (previously a danglingendedwas sent for a path the peer never saw).Pre-06 versions keep their frozen single-
ANNOUNCE_BROADCASTframing (inner status byte); all forms are version-gated at encode/decode.Opt-in gating (not advertised by default)
lite-06's wire format is work-in-progress, so it is never advertised or negotiated by default. The ALPN is
moq-lite-06-wip(wire code0xff0dad06), but it is deliberately absent frommoq_net::ALPNS,Versions::all(), and the JS defaultprotocolslist. A peer only reaches it when both sides explicitly opt in (e.g.--version moq-lite-06-wip/client_config.version = ["moq-lite-06-wip"]), which is enough to exercise it in tests. The version stays fully defined (code / ALPN /FromStrmappings), so an opt-in set negotiates normally. Finalizing is then a rename of the internalLite06Wipmarker and dropping the-wipfrom the ALPN.The moq-native raw-QUIC accept path (noq/quinn/quiche) previously recognized ALPNs against the global
moq_net::ALPNSconst, which would reject an opt-in ALPN that isn't in the default set. It now recognizes the server's own configured ALPNs (rustls only negotiates an ALPN the server offered).Cross-package sync
rs/moq-net: wire format (AnnounceBroadcastnow implsEncode/Decodedirectly, likeSubscribeResponse), publisher/subscriber id bookkeeping,Version::Lite06Wipplumbing (client/server ALPN arms,Handshake::Lite05generalized toLiteSetup), and the opt-in exclusion fromALPNS/all().rs/moq-native: raw-QUIC accept ALPN recognition keyed off the server's configured versions (noq/quinn/quiche).js/net: mirrored (Version.DRAFT_06,ALPN_06_WIP, union-shapedAnnounceBroadcastwithencode/decodeAnnounceBroadcastwriting the outer type + length likeencodeSubscribeResponse), and excluded from the defaultprotocolslist.drafts/:draft-lcurley-moq-lite.mdupdated in-repo — the single## ANNOUNCE_BROADCASTsection is replaced by## ANNOUNCE_START/## ANNOUNCE_END/## ANNOUNCE_RESTART, plus the Announce-stream prose, cross-references, and changelog.doc/concept: no change needed; it documents theannounced(prefix)API surface, which is unchanged.Public API changes
rs/moq-net:lite::VersiongainsLite06Wip;lite::Version::has_announce_id()added;lite::AnnounceBroadcastgainsEndedId { id }andRestart { id, hops }variants and switches fromMessageto a directEncode/Decodeimpl (breaking for exhaustive matches, hence dev).js/net:AnnounceBroadcastis a discriminated union (active/ended/endedId/restart) withencodeAnnounceBroadcast/decodeAnnounceBroadcast[Maybe]functions (breaking);Version.DRAFT_06,ALPN_06_WIP,hasAnnounceIdadded.Testing
ANNOUNCE_ENDsize check).rs/moq-native/tests/broadcast.rsandjs/net/src/integration.test.ts, both sides pinned tomoq-lite-06-wip.NEWEST_LITE, smoke) stay on lite-05, confirming lite-06 is not picked by default.just checkpasses.🤖 Generated with Claude Code