Skip to content

moq-lite-05: sync wire with drafts HEAD (SETUP stream, broadcast epoch, drop cache hint, rename ANNOUNCE)#1847

Merged
kixelated merged 5 commits into
devfrom
claude/moq-lite-05-sync-tzhxi2
Jun 21, 2026
Merged

moq-lite-05: sync wire with drafts HEAD (SETUP stream, broadcast epoch, drop cache hint, rename ANNOUNCE)#1847
kixelated merged 5 commits into
devfrom
claude/moq-lite-05-sync-tzhxi2

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Syncs the moq-lite-05 (Lite05Wip / DRAFT_05_WIP) implementation with the latest commits on moq-dev/drafts, across Rust (rs/moq-net), TypeScript (js/net), and the concept docs. All wire changes are gated to lite-05+; older drafts are unaffected.

Drafts covered

Draft PR Change Status
#35 Broadcast Epoch + rename ANNOUNCE messages ✅ new
#34 Remove Publisher Cache hint from TRACK_INFO ✅ new
#28 Path Parameter wording (per-hop setup metadata) ✅ docs
#27 Path Setup Parameter for URI-less transports ✅ new
#26 SETUP message + negotiated Probe capability levels ✅ new
#24 / #25 / #32 / #33 Frame Start to FETCH / TRACK stream / drop per-frame duration / fixed-width Hop ID ✅ already landed, re-verified

What changed

#35 — Broadcast Epoch + ANNOUNCE renames

  • Wire renames (names only; stream/message IDs unchanged): ANNOUNCEANNOUNCE_BROADCAST, ANNOUNCE_INTERESTANNOUNCE_REQUEST. Rust types Announce/AnnounceInterest and the JS Announce/AnnounceInterest classes renamed to match (both internal to the private lite module / package surface).
  • New per-broadcast Epoch, carried end-to-end. BroadcastInfo.epoch is a SystemTime defaulting to now() (the instant the instance is created), encoded on the wire as milliseconds since 2020‑01‑01 UTC (a varint after the suffix, before the hop chain). JS represents it as the same ms‑since‑2020 number.
  • The origin's route selection (route_key) now prefers the newer instance (larger epoch) among equal‑length hop chains, then falls back to the existing deterministic hash tie‑break. Shortest hop chain still wins first, preserving routing; the epoch and hops are forwarded unchanged so a cluster still converges.

#34 — Remove the Publisher Cache hint

  • The cache duration is gone from the TRACK_INFO wire message. Retention is now best‑effort, not a guaranteed minimum. The local retention window (model::TrackInfo.cache) stays and falls back to DEFAULT_CACHE on the subscriber.

#26 / #27 — SETUP stream

  • New unidirectional Setup Stream (DataType::Setup = 1). Each endpoint opens it once, sends a single SETUP message advertising its capabilities, and FINs. The two SETUPs are independent (neither side blocks on the peer's before opening other streams).
  • Probe capability negotiation (None/Report/Increase; unknown future levels saturate to Increase). The subscriber now only opens a PROBE stream if the peer advertised Probe >= Report. Older versions keep probing unconditionally.
  • Path Setup Parameter for transports with no request URI. Client::with_path (Rust) sets the path advertised in the client's SETUP; servers never send one. The peer's SETUP (incl. path) is decoded and recorded.
  • The SETUP body reuses the parameter framing (the Parameters bag gained typed varint/bytes accessors in Rust; a private mirror in JS).

#28 + concept docs

  • doc/concept/layer/moq-lite.md updated: SETUP capabilities + URI‑less path, broadcast epoch convergence, and the cache reframed as a best‑effort local window (it previously referenced the removed SUBSCRIBE_OK field).

Cross-package sync

  • rs/moq-netjs/net: mirrored (announce/track wire, the SETUP stream, probe gating). Browser↔relay interop is preserved now that both ends exchange a Setup uni stream.
  • doc/concept: updated as above.

Not in scope (follow-up)

  • Wiring the received Path into relay routing for URI-less bindings (qmux over TCP/unix). The Path is exchanged and decoded on both ends, but threading it into the relay's origin scoping is a larger native/relay feature left for a separate PR.
  • js/net has no multi-route origin tree, so the epoch tie-break is Rust-only there (the JS side decodes the epoch but has nothing to dedup).

Test plan

  • cargo test -p moq-net --lib — 396 passed
  • cargo test -p moq-relay --lib — 123 passed
  • cargo check on hang, moq-relay, libmoq, moq-ffi, moq-mux, moq-bench
  • cargo clippy -p moq-net — clean; cargo fmt
  • cd js/net && bun test — 189 passed; bun run check (tsc) + biome check clean
  • Manual browser↔relay lite-05 smoke test (recommend before merge, since SETUP-stream interop only fully surfaces at runtime)

One design point worth a reviewer's eye: the epoch as SystemTime-now means BroadcastInfo::new() stamps the current wall clock, so two locally-created broadcasts at the same path now resolve by creation time (newer wins) rather than purely by hash. Cross-route/relayed cases are unaffected (epoch is forwarded unchanged).

🤖 Generated with Claude Code

https://claude.ai/code/session_0118VcLtfuukFERQ8ito5dUG

(Written by Claude)


Generated by Claude Code

claude added 5 commits June 21, 2026 01:40
…, add broadcast epoch, rename ANNOUNCE)

Brings the moq-lite-05 (Lite05Wip) wire and naming in line with the two latest
drafts commits:

- #34: remove the Publisher Cache hint from TRACK_INFO. Retention is now a
  best-effort cache, not a guaranteed minimum, so the field no longer rides the
  wire. The local retention window (model TrackInfo.cache) stays and falls back
  to DEFAULT_CACHE on the subscriber.
- #35: rename ANNOUNCE -> ANNOUNCE_BROADCAST and ANNOUNCE_INTEREST ->
  ANNOUNCE_REQUEST (wire names only; stream/message IDs unchanged), and add a
  per-broadcast Epoch.

The epoch is carried end-to-end: BroadcastInfo.epoch is a SystemTime defaulting
to now (the instant the instance was created), encoded on the wire as
milliseconds since 2020-01-01 UTC. The origin's route selection now prefers the
newer instance (larger epoch) among equal-length routes, then falls back to the
existing deterministic hash tie-break, so a cluster still converges. Shortest
hop chain still wins first to preserve routing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118VcLtfuukFERQ8ito5dUG
…fts #26/#27)

Adds the lite-05 SETUP message exchanged on a unidirectional Setup Stream
(DataType::Setup = 1). Each endpoint opens the stream once, sends a single SETUP
advertising its capabilities, and FINs. The two SETUPs are independent: neither
side blocks on the peer's before opening other streams.

- #26: SETUP message + negotiated Probe capability levels (None/Report/Increase).
  The SETUP body reuses the parameter framing (Parameters gained typed varint/
  bytes accessors). The subscriber now gates opening a PROBE stream on the peer
  having advertised Probe >= Report in its SETUP; unknown future levels saturate
  to Increase. Older versions have no Setup Stream and keep probing unconditionally.
- #27: Path Setup Parameter for URI-less transports. Client::with_path sets the
  request path advertised in the client's SETUP (native QUIC / qmux over TCP/TLS);
  servers never send one. The peer's SETUP (incl. path) is decoded and recorded;
  wiring the received path into relay routing is left for a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118VcLtfuukFERQ8ito5dUG
…ort cache

Aligns doc/concept/layer/moq-lite.md with the drafts #26/#27/#34/#35 sync:

- SETUP now advertises per-endpoint capabilities (e.g. bitrate probing) and, on
  URI-less transports, the request path. The two SETUPs are independent.
- Broadcasts carry an epoch so duplicate/republished advertisements converge on
  the newest instance.
- The per-track cache is described as a best-effort local retention window, no
  longer announced on the wire (it previously referenced the removed SUBSCRIBE_OK
  field). Also drops the stale per-hop wording in line with drafts #28.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118VcLtfuukFERQ8ito5dUG
Browser-side counterpart to the Rust lite-05 SETUP work, required for
browser<->relay interop now that each endpoint exchanges a SETUP on a uni
stream (DataType.Setup = 1):

- New lite/setup.ts: ProbeLevel (None/Report/Increase, unknown saturates to
  Increase) and a size-prefixed Setup message over a private Parameters bag
  (varint count + id/length/value triples), gated to DRAFT_05_WIP+.
- On lite-05 session start the connection sends our SETUP (probe = Report; path
  undefined, since WebTransport carries the URI), decodes the peer's SETUP in the
  uni dispatch, and threads it to the Subscriber.
- runProbe() now waits for and gates on the peer's advertised probe level on
  lite-05+; older drafts probe unconditionally as before.

(Written by Claude)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118VcLtfuukFERQ8ito5dUG
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118VcLtfuukFERQ8ito5dUG
@kixelated kixelated merged commit cfa1d26 into dev Jun 21, 2026
1 check passed
@kixelated kixelated deleted the claude/moq-lite-05-sync-tzhxi2 branch June 21, 2026 03:10
kixelated pushed a commit that referenced this pull request Jun 21, 2026
dev advanced 3 commits while this PR was open (#1845 PTS-exposing TS Export +
PCR-paced SRT egress, #1847 moq-lite-05 wire sync, #1819 always-on hardware
encoders). Re-merged dev and reconciled two conflicts:

- nix/overlay.nix: kept this PR's cargo+sccache CI direction (dev's tip still
  carries the crane `moqChecks`; the cargo switch lives on main, #1821).
- rs/moq-mux/src/container/ts/export.rs: combined dev's #1845 Frame-returning
  `Export::next` (PTS/keyframe-stamped) with this PR's generic `catalog::Catalog`
  trait (main's #1815 mpegts rename). Updated the moq-cli drain helper to read
  `frame.payload` and refreshed two stale `scte35::Ext` comments.

Verified: moq-mux (279), moq-cli, moq-srt tests pass; workspace clippy -D
warnings and fmt clean (excluding the crates that need libva/gstreamer system
libs unavailable in this sandbox: moq-video/libmoq/moq-boy/moq-gst); JS
type-checks and biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BQ9o9paZnRLpYRgbyjUwFV
@kixelated kixelated mentioned this pull request Jun 21, 2026
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.

2 participants