From 0cf25c4d12a7de7befa7386ddce9b190fae5a642 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 20 Oct 2026 23:47:16 -0700 Subject: [PATCH 1/9] quest: claim m1/audit-docs Co-Authored-By: Claude Opus 5.5 From cb315ed6a8a5b15802bc93edd4ccd57c9cd0e613 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 20 Oct 2026 23:59:21 -0700 Subject: [PATCH 2/9] docs(readme): fix the demo port and the moq-tokio and moq-mux rows The demo serves on Vite's default 5173, moq-tokio runs on moq-quic rather than Quinn, and HLS moved out of moq-mux into moq-hls. Co-Authored-By: Claude Opus 5.5 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b43df709d6..9669abd5cbf 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The quickest way to see it in action (requires [Nix](https://nixos.org/download. nix develop -c just ``` -Then visit . Don't have Nix? See the [demo guide](https://doc.moq.dev/setup/) for manual setup. +Then visit . Don't have Nix? See the [demo guide](https://doc.moq.dev/setup/) for manual setup. ## Architecture @@ -85,11 +85,11 @@ This repository provides both [Rust](rs) and [TypeScript](js) libraries with sim | [moq-net](rs/moq-net) | The networking layer: real-time pub/sub with built-in caching, fan-out, and prioritization. Negotiates either the `moq-lite` or `moq-transport` wire protocol. | [![docs.rs](https://docs.rs/moq-net/badge.svg)](https://docs.rs/moq-net) | | [moq-relay](rs/moq-relay) | A clusterable relay server. This relay performs fan-out connecting multiple clients and servers together. | | | [moq-auth](rs/moq-auth) | The authorization contract `moq-relay` speaks: requests, grants, leases, and the JWT that rides them. `moq auth` is the CLI. | [![docs.rs](https://docs.rs/moq-auth/badge.svg)](https://docs.rs/moq-auth) | -| [moq-tokio](rs/moq-tokio) | Opinionated helpers to configure a Quinn QUIC endpoint. It's harder than it should be. | [![docs.rs](https://docs.rs/moq-tokio/badge.svg)](https://docs.rs/moq-tokio) | +| [moq-tokio](rs/moq-tokio) | Connect and listen over QUIC, WebTransport, WebSocket, TCP/TLS, and Unix sockets, plus optional iroh and WebRTC. | [![docs.rs](https://docs.rs/moq-tokio/badge.svg)](https://docs.rs/moq-tokio) | | [moq-c](rs/moq-c) | C bindings for `moq-net`. | [![docs.rs](https://docs.rs/moq-c/badge.svg)](https://docs.rs/moq-c) | | [hang](rs/hang) | Media-specific encoding/streaming layered on top of `moq-net`. Can be used as a library. | [![docs.rs](https://docs.rs/hang/badge.svg)](https://docs.rs/hang) | | [moq-cli](rs/moq-cli) | A CLI for publishing media to MoQ relays. | | -| [moq-mux](rs/moq-mux) | Media muxers and demuxers (fMP4/CMAF, HLS) for importing content into MoQ broadcasts. | [![docs.rs](https://docs.rs/moq-mux/badge.svg)](https://docs.rs/moq-mux) | +| [moq-mux](rs/moq-mux) | Media muxers and demuxers (fMP4/CMAF, MPEG-TS, FLV, Matroska) for importing content into MoQ broadcasts. | [![docs.rs](https://docs.rs/moq-mux/badge.svg)](https://docs.rs/moq-mux) | | [moq-gst](rs/moq-gst) | A GStreamer plugin for publishing or consuming MoQ broadcasts. Not built by default; requires GStreamer dev libraries. | | ### TypeScript From 1aee419a96e1461a18d5b2164462ce2d0c922962 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 20 Oct 2026 23:59:21 -0700 Subject: [PATCH 3/9] docs(concept): https:// dials WebTransport, and WebSocket rides either web listener Co-Authored-By: Claude Opus 5.5 --- doc/concept/transport.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/concept/transport.md b/doc/concept/transport.md index 001d828e1c1..cddcb32583f 100644 --- a/doc/concept/transport.md +++ b/doc/concept/transport.md @@ -42,7 +42,7 @@ connection (`wss://`) and keep whichever wins. A small multiplexer, [qmux](/draft/qmux-websocket), carries MoQ streams over the socket. It works everywhere but cannot escape TCP head-of-line blocking, so priority and resets only help once bytes leave the TCP queue. The fallback is automatic in every -client; the relay enables it with `[web.https]`. A session that lands on +client; the relay serves it on its `[web.http]` or `[web.https]` listener. A session that lands on WebSocket stays there until it ends; the next connect races again. ## Raw QUIC (native) @@ -50,8 +50,8 @@ WebSocket stays there until it ends; the next connect races again. Native clients dial the relay directly with the MoQ ALPN, skipping the HTTP/3 handshake. The URL path and `?jwt=` token travel in the MoQ `SETUP` message instead of a `CONNECT` request, so the server sees the same thing either way. -`moq-tokio` picks this automatically for `https://` URLs; use `moql://` or -`moqt://` to force it. +`moq-tokio` dials WebTransport for `https://` URLs; use `moql://` or `moqt://` +for raw QUIC. ## TCP and Unix sockets (local workers) From 14371c75e11b08369686570958845bc9a7a68cf6 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 20 Oct 2026 23:59:21 -0700 Subject: [PATCH 4/9] docs(bin): fix the RTMP FLAC reason and add Opus to SRT's codecs hang has a FLAC codec; the FLV import is what drops it. TS import handles Opus. Co-Authored-By: Claude Opus 5.5 --- doc/bin/rtmp.md | 4 ++-- doc/bin/srt.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/bin/rtmp.md b/doc/bin/rtmp.md index 296262ebdde..df5ff22bcb4 100644 --- a/doc/bin/rtmp.md +++ b/doc/bin/rtmp.md @@ -53,5 +53,5 @@ carries the best of each. Implemented in pure Rust (no librtmp). The CLI speaks plaintext `rtmp://` only, so stream keys cross the network unencrypted. The library adds RTMPS on the same port when the embedder supplies a TLS config, and can refuse plaintext -there. FLAC enhanced-audio payloads are dropped because hang has no catalog -codec for them. MP3 works in both legacy and enhanced audio tags. +there. FLAC enhanced-audio payloads are dropped because the FLV import does not +map them. MP3 works in both legacy and enhanced audio tags. diff --git a/doc/bin/srt.md b/doc/bin/srt.md index 7f7ee1efc6a..1e0069edfc4 100644 --- a/doc/bin/srt.md +++ b/doc/bin/srt.md @@ -8,8 +8,8 @@ description: SRT contribution and playback `moq import srt` accepts SRT pushes (`--listen`) or pulls from a remote SRT source (`--connect`); `moq export srt` serves SRT to players or pushes to a remote. The payload is MPEG-TS, so the same codecs and behavior as -[`import ts`](/bin/cli) apply: H.264/H.265 video and AAC, MP2, AC-3, or E-AC-3 -audio. A damaged unit is dropped and the session stays up; video resumes at its +[`import ts`](/bin/cli) apply: H.264/H.265 video and AAC, MP2, AC-3, E-AC-3, or +Opus audio. A damaged unit is dropped and the session stays up; video resumes at its next keyframe, freezing for up to one GOP. ```bash From 52b6745d52647e4230f5d12cea2b7a7b0425d6b7 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 20 Oct 2026 23:59:22 -0700 Subject: [PATCH 5/9] docs(moq-c): ranges are a per-subscription read filter #5929 made each subscription read only its own ranges; moq.h still described the aggregate read. Co-Authored-By: Claude Opus 5.5 --- rs/moq-c/src/api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rs/moq-c/src/api.rs b/rs/moq-c/src/api.rs index c0004025181..4457dd6843e 100644 --- a/rs/moq-c/src/api.rs +++ b/rs/moq-c/src/api.rs @@ -594,8 +594,8 @@ pub struct moq_subscription { /// The spans of the track to deliver, or NULL for everything `max_delay_us` still /// considers fresh. A non-NULL pointer with `ranges_len` 0 asks for nothing. /// - /// A request to the publisher, aggregated across every subscriber. Reads start at the - /// lowest group a range starts at, and stop past the last absolute end. + /// A request to the publisher, aggregated across every subscriber, and this + /// subscription's read filter: it reads only the groups its own ranges cover. pub ranges: *const moq_range, pub ranges_len: usize, From 8e2572c3b4093353afd386723ac3e47795c7bb78 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Wed, 21 Oct 2026 00:18:46 -0700 Subject: [PATCH 6/9] chore(shaper): lint missing docs moq-shaper was already fully documented; the lint keeps it so. Co-Authored-By: Claude Opus 5.5 --- rs/moq-shaper/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rs/moq-shaper/src/lib.rs b/rs/moq-shaper/src/lib.rs index b7933e45555..1c1c28ce0fa 100644 --- a/rs/moq-shaper/src/lib.rs +++ b/rs/moq-shaper/src/lib.rs @@ -18,6 +18,8 @@ //! model that keeps the order, one link shared by every client, batches, steps, //! and named profiles loaded as a [`Preset`]. The README says why each exists. +#![warn(missing_docs)] + use std::{ cmp::Reverse, collections::{BTreeMap, BinaryHeap, HashMap, hash_map}, From 099c73c161535df640e0f01a318c7440a7116683 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Wed, 21 Oct 2026 00:22:11 -0700 Subject: [PATCH 7/9] docs(wasm): document Group.sequence and lint missing docs The reads resolve to undefined, not null, matching their TypeScript return types. Co-Authored-By: Claude Opus 5.5 --- rs/moq-wasm/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rs/moq-wasm/src/lib.rs b/rs/moq-wasm/src/lib.rs index 63c2172567d..89877491265 100644 --- a/rs/moq-wasm/src/lib.rs +++ b/rs/moq-wasm/src/lib.rs @@ -20,6 +20,7 @@ // Browser-only crate. Empty on native so `cargo check --workspace` stays green. #![cfg(target_arch = "wasm32")] +#![warn(missing_docs)] use std::cell::RefCell; use std::pin::pin; @@ -218,7 +219,7 @@ pub struct Track { #[wasm_bindgen] impl Track { - /// Receive the next group in arrival order, or `null` when the track ends. + /// Receive the next group in arrival order, or `undefined` when the track ends. #[wasm_bindgen(js_name = recvGroup, unchecked_return_type = "Promise")] pub fn recv_group(&self) -> Promise { let cell = self.inner.clone(); @@ -254,12 +255,13 @@ pub struct Group { #[wasm_bindgen] impl Group { + /// The group's sequence number within its track. #[wasm_bindgen(getter)] pub fn sequence(&self) -> u64 { self.sequence } - /// Read the next frame in the group, or `null` at the end of the group. + /// Read the next frame in the group, or `undefined` at the end of the group. #[wasm_bindgen(js_name = readFrame, unchecked_return_type = "Promise")] pub fn read_frame(&self) -> Promise { let cell = self.inner.clone(); From 5a839ee078c2a1da898d3a1dce9cd61309c38706 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Wed, 21 Oct 2026 00:25:38 -0700 Subject: [PATCH 8/9] quest: finish the m1 documentation audit and add the m2 run Co-Authored-By: Claude Opus 5.5 --- quest/m1/README.md | 1 - quest/m1/audit-docs.md | 57 ----------------------------------- quest/m2/README.md | 1 + quest/m2/audit-docs.md | 68 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 58 deletions(-) delete mode 100644 quest/m1/audit-docs.md create mode 100644 quest/m2/audit-docs.md diff --git a/quest/m1/README.md b/quest/m1/README.md index 0cec85655e8..ae9a1ef4767 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -126,7 +126,6 @@ lands before the cut. - [Test cost audit](/quest/m1/audit-test-cost.md) - the slowest, flakiest, and least valuable tests are fixed, deleted, or planned - [Interop report](/quest/m1/interop-report.md) - nightly Interop results publish as a color-coded matrix on the Pages site instead of only in logs - [CI workflow audit](/quest/m1/audit-ci.md) - every workflow and job gives a signal someone sees, at a cost that signal justifies, or is fixed, moved, or deleted -- [Documentation audit](/quest/m1/audit-docs.md) - stale pages, examples, links, and undocumented exports are fixed or planned - [Artifact size audit](/quest/m1/audit-size.md) - binary, FFI, WASM, and bundle growth since the m0 run is explained, fixed, or planned ## Related diff --git a/quest/m1/audit-docs.md b/quest/m1/audit-docs.md deleted file mode 100644 index 2d42dc72f42..00000000000 --- a/quest/m1/audit-docs.md +++ /dev/null @@ -1,57 +0,0 @@ -# [M] Documentation audit - -## Goal - -Docs match the code: stale pages, broken examples, broken links, and -undocumented exported symbols are fixed or planned. - -## Plan - -Recurs once per major release (decided 2026-10-19). The PR that finishes -this run also adds the next one with the same file name at the end of the next -milestone's `Required` (m0 to m1, m1 to m2). The successor keeps the Goal -and this paragraph; the rest of its Plan is rewritten with what this run -learned: baselines, results, and what to check first. A successor placed in m2 -also lists the [release cut](/quest/m2/release/cut.md) under `Required`, so it -waits for the release in flight to ship. Only `/quest-delete` ends the -recurrence. Fixes land in the run's PR, one commit each, rather than as follow-ups. -Only a change that needs a maintainer decision (public API, scope) or is -independently landable and too large to review alongside the rest becomes a -follow-up through `/quest-plan`. - -Follow `doc/AGENTS.md` for what belongs in `doc/`. The m0 run (2026-10-19) -fixed stale codec, driver, auth, snapshot, Go wrapper, and stats-example -claims, documented every public item in hang, moq-archive, moq-auth, -moq-relay, and moq-nvenc, and filled the core JS packages' gaps. Start by -comparing against these baselines: - -- Rust: 26 crates set `#![warn(missing_docs)]`. Count the rest with - `cargo rustdoc -p --lib --all-features -- -W missing_docs`; only - `--all-features` reaches feature-gated items, which is how the m0 run found - moq-auth's undocumented server refusals, and `just rs wasm` reaches - wasm-only items such as kio's `MaybeSend`. `moq-mux`, `moq-ffi`, and `moq-c` - have follow-ups. `moq-video`, `moq-audio`, and `moq-sock` are documented on - Linux but stay unlinted: they gate public items on macOS, Windows, and - Android, and the dev shell has no std for those targets, so a lint could - only be verified in the merge queue's platform jobs. `moq-gst` cannot lint - because `gst::plugin_define!` emits undocumented public items. `moq-v4l` - is a fork of the `v4l` crate with 222 undocumented hand-written items beside - its generated `sys` bindings; decide whether a fork earns docs before - writing them. `libmoq` and the `moq-native` tombstone export nothing. -- JS: no tool checks doc comments; the [follow-up](/quest/m1/docs-js.md) adds - one. Until it lands, walk each published package's `exports` with the - TypeScript compiler API. The m0 baseline was 608 exports with 84 - undocumented and 676 public class members with 159 undocumented, nearly all - in `@moq/publish`, `@moq/watch`, and `@moq/boy`. -- Links: GET (not HEAD) every external URL in `doc/` with a browser user - agent; 262 answered except npmjs.com package pages, which refuse - non-browser clients (check `registry.npmjs.org/` instead), and - placeholder hosts. crates.io answers 200 to such a GET. -- CLI: all complete shell examples parse with `--help` appended against a - build with `capture,play,transcode,iroh,openh264`, which unknown flags fail - but bad values do not. `gst-inspect-1.0` of a debug `moq-gst` build lists - every element and pad property `doc/bin/gstreamer.md` names. -- Cross-Package Sync: walked from the 2026-10-16 release cut (`d0b086e71b`) - through `9b90cdd569`. Walk the next run from there. The table's Go row - and `rs/moq-ffi/AGENTS.md` name `go/wrapper/moq`, which does not exist; - the wrapper is `go/wrapper/*.go` and its subpackages. diff --git a/quest/m2/README.md b/quest/m2/README.md index 502885431fa..4383ec620c6 100644 --- a/quest/m2/README.md +++ b/quest/m2/README.md @@ -176,3 +176,4 @@ ranked just below deterministic TS legs, which it requires. - [Relay metrics through prometheus-client](/quest/m2/relay-prometheus-client.md) - `/metrics` renders through the maintained client with the same series - [Dead routes on IETF name their cause](/quest/m2/js-ietf-dead-route-error.md) - a JS subscription on a dead moq-transport session ends with the session error, not `unauthorized` - [Error cleanups](/quest/m2/error-cleanups.md) - delete the unused `Error::SessionClosed`; raw transport failures already map to `Unroutable` +- [Documentation audit](/quest/m2/audit-docs.md) - repeat the docs audit after the release ships, against the m1 baselines diff --git a/quest/m2/audit-docs.md b/quest/m2/audit-docs.md new file mode 100644 index 00000000000..7821d24bcef --- /dev/null +++ b/quest/m2/audit-docs.md @@ -0,0 +1,68 @@ +# [M] Documentation audit + +## Goal + +Docs match the code: stale pages, broken examples, broken links, and +undocumented exported symbols are fixed or planned. + +## Plan + +Recurs once per major release (decided 2026-10-19). The PR that finishes +this run also adds the next one with the same file name at the end of the next +milestone's `Required` (m0 to m1, m1 to m2). The successor keeps the Goal +and this paragraph; the rest of its Plan is rewritten with what this run +learned: baselines, results, and what to check first. A successor placed in m2 +also lists the [release cut](/quest/m2/release/cut.md) under `Required`, so it +waits for the release in flight to ship. Only `/quest-delete` ends the +recurrence. Fixes land in the run's PR, one commit each, rather than as follow-ups. +Only a change that needs a maintainer decision (public API, scope) or is +independently landable and too large to review alongside the rest becomes a +follow-up through `/quest-plan`. + +Follow `doc/AGENTS.md` for what belongs in `doc/`. The docs site deploys from +`release`, so a page describing an unreleased package (such as `@moq/video`, +first published by the release cut) is expected to 404 on its registry until +then. The m1 run (2026-10-21) found the stale claims in pages no PR had touched +for a while: the root `README.md` crate table, `doc/concept/transport.md`, and +the codec lists in `doc/bin/rtmp.md` and `srt.md`. Read those kinds of pages +claim by claim against the code first; the pages recent PRs edit are the +freshest. Baselines: + +- Rust: 28 crates set `#![warn(missing_docs)]`; m1 added `moq-shaper` and + `moq-wasm`. Count the rest with + `cargo rustdoc -p --lib --all-features -- -W missing_docs`, and + `moq-wasm` with `--target wasm32-unknown-unknown`, since it is empty on + native. `moq-auth` is ambiguous with its crates.io copy, so pass its + `path+file://` spec. Every linted crate was clean with all features. + `moq-audio`, `moq-video`, and `moq-sock` were also clean on Linux but stay + unlinted for their macOS, Windows, and Android items. `moq-gst` has 3 items + from `gst::plugin_define!`. `moq-v4l` reports 3108, nearly all its generated + `sys` bindings; whether the fork earns docs is still undecided. `moq-mux`, + `moq-ffi`, and `moq-c` had follow-ups in flight + ([docs-mux](https://github.com/moq-dev/moq/pull/6088), + [docs-bindings](https://github.com/moq-dev/moq/pull/6091)); check that they + landed and set the lint. +- JS: the [docs-js](https://github.com/moq-dev/moq/pull/6163) follow-up adds a + build check for undocumented exports. If it landed, run it; if not, walk each + published package's `exports` with the TypeScript compiler API. +- Links: GET (not HEAD) every external URL in `doc/` with a browser user + agent. 316 URLs: all answered except placeholder and local hosts, relay + URLs that only speak MoQ, npmjs.com and w3.org pages that refuse + non-browser clients, and the unreleased items above. Check npm packages on + `registry.npmjs.org/` and crates on the crates.io API, since + crates.io pages answer 200 to anything. `README.md`'s `moq-c` badge waits on + the crate's first publish. +- CLI: all 68 shell invocations in `doc/`, `README.md`, and + `rs/moq-cli/README.md` parse with `--help` appended against a build with + `capture,play,transcode,iroh,openh264`, after substituting a URL for the + elided `moq ...` connect. Unknown flags fail but bad values do not. + `gst-inspect-1.0` of a debug `moq-gst` build lists every element and pad + property `doc/bin/gstreamer.md` names. +- Cross-Package Sync: walked from `9b90cdd569` through `7d2a91fe66`. Walk the + next run from there. Go has no `Client` failure accessor because `Dial` + returns only once connected; the maintainer chose to leave that until a Go + caller needs it, so it is not a gap. + +## Required + +- [Release cut](/quest/m2/release/cut.md) - the release in flight ships before this run starts From cd40579c2f0489ede6ce00fa0a0edae3f3c13fbe Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Wed, 21 Oct 2026 16:09:36 -0700 Subject: [PATCH 9/9] docs: point the demo URL at watch.html Vite's root has no index.html, so the bare origin shows nothing. Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- doc/bin/demo.md | 2 +- doc/setup/index.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9669abd5cbf..2465e66cb3c 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The quickest way to see it in action (requires [Nix](https://nixos.org/download. nix develop -c just ``` -Then visit . Don't have Nix? See the [demo guide](https://doc.moq.dev/setup/) for manual setup. +It opens the watch, publish, and stats pages in your browser, or visit . Don't have Nix? See the [demo guide](https://doc.moq.dev/setup/) for manual setup. ## Architecture diff --git a/doc/bin/demo.md b/doc/bin/demo.md index 3e1b8d9436d..a2ae9ef6bc5 100644 --- a/doc/bin/demo.md +++ b/doc/bin/demo.md @@ -11,7 +11,7 @@ Each runs locally from a checkout. The web demo and MoQ Boy also live at ## Web demo ```bash -just # relay + Big Buck Bunny + the web UI at http://localhost:5173 +just # relay + Big Buck Bunny + the web UI at http://localhost:5173/watch.html ``` A Vite app in [`demo/web/`](https://github.com/moq-dev/moq/tree/main/demo/web) diff --git a/doc/setup/index.md b/doc/setup/index.md index 4b8e238b267..2d2ec7dad9e 100644 --- a/doc/setup/index.md +++ b/doc/setup/index.md @@ -42,7 +42,7 @@ Windows users should run `setup.bat` first; see [Development](/setup/dev#windows 1. [moq-relay](/bin/relay/) on `localhost:4443` with a generated certificate and anonymous access. 2. [moq-cli](/bin/cli) publishing Big Buck Bunny through the relay. -3. The [web demo](/bin/demo) at [localhost:5173](http://localhost:5173), where you can watch the stream or publish your camera. +3. The [web demo](/bin/demo) at [localhost:5173/watch.html](http://localhost:5173/watch.html), where you can watch the stream or publish your camera. ## Skip the relay