Repository navigation
quest: plan the API shape fixes from the release-vs-main audit #8191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # [S] One assets() for every hosted file | ||
|
|
||
| ## Goal | ||
|
|
||
| A page that serves the player's files itself (for a strict | ||
| `Content-Security-Policy` with no `blob:` workers) calls one `assets(url)`, | ||
| and that call also points the libav AAC polyfill at the hosted wasm. Today | ||
| `@moq/watch` and `@moq/publish` each carry an identical copy of `assets()` | ||
| (`js/watch/src/assets.ts`, `js/publish/src/assets.ts`), and an app that | ||
| needs the polyfill must also import `@moq/libav` and set its mutable | ||
| `LibAV.base`, a transitive dependency our API never mentions. | ||
|
|
||
| ## Plan | ||
|
|
||
| Found by the 2026-11-07 API shape audit (browser media). Move `assets` and | ||
| its resolver into `@moq/hang`, the shared dependency whose | ||
| `Util.Libav.polyfill()` (`js/hang/src/util/libav.ts`) loads libav, and have | ||
| the polyfill take its base from it. `@moq/watch` and `@moq/publish` | ||
| re-export it, so their existing `assets()` callers keep working and nothing | ||
|
Comment on lines
+16
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| breaks. `@moq/libav` stays an implementation dependency. Future hosted files | ||
| (the watch worker) join the same call. Test it on the CSP demo pages. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # [S] Transports report no stream credit | ||
|
|
||
| ## Goal | ||
|
|
||
| `moq_net::transport::StreamCredit`, `Dir`, and the `poll::Session::stream_credit` | ||
| hook are gone, so no transport implements a credit API. The open line | ||
|
Comment on lines
+5
to
+6
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| (`rs/moq-net/src/transport/open.rs`) decides when a waiting open preempts a | ||
| lower-ranked stream from its own state, as `js/net` already does, and an | ||
| open waiting on something other than credit still never triggers a reset. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-11-07 (maintainer, /quest-plan from the API shape audit): | ||
| ✅ "Delete, no hooks" (rejected: keeping the hook and recording why). This | ||
| follows the [moq-dev/moq#7894](https://github.com/moq-dev/moq/pull/7894) | ||
| reversal recorded in this epic ("the signal is the open line's waiting | ||
| state, with no transport credit or blocked API") and overrides | ||
| [moq-dev/moq#8088](https://github.com/moq-dev/moq/pull/8088)'s refutation, | ||
| which kept the hook because the open line reads it. | ||
|
|
||
| The hook exists today so an open waiting on a WebTransport stream header is | ||
| not mistaken for a credit wait (`make_room`, open.rs). Remove that case at | ||
| its source, for example by having a transport's open complete only once | ||
| credit is granted and write the header after, so a pending head always means | ||
| credit. Implementers of `poll::Session` (moq-tokio, moq-uring, qmux, the | ||
| memory transport) drop their implementations. | ||
|
|
||
| Breaking for transport implementers; the Impact section says what replaces | ||
| the hook. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # [XS] Watch sources default to the decoder's probe | ||
|
|
||
| ## Goal | ||
|
|
||
| A composer that builds `@moq/watch`'s `Audio.Source` or `Video.Source` | ||
| without `in.supported` gets playback. Today the input defaults to | ||
| `undefined`, and "nothing is selected until one is provided" | ||
| (`js/watch/src/audio/source.ts`), so forgetting it is silent non-playback. | ||
| When `in.supported` is absent, the source uses its decoder's `supported` | ||
| probe. | ||
|
|
||
| ## Plan | ||
|
|
||
| Found by the 2026-11-07 API shape audit (browser media). Additive: callers | ||
| that pass `supported`, such as the `<moq-watch>` element, are unchanged. Add a test that a source built without it selects a | ||
| rendition. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # [L] Small API fixes before the cut | ||
|
|
||
| ## Goal | ||
|
|
||
| The surfaces `main` adds since `release` follow the repository's API rules | ||
| before the cut publishes them: one path and one spelling per item, names by | ||
| role, no dead or unreachable public items, no setter that a caller can apply | ||
| to the wrong role, and Rust, JS, and the bindings mirrored. Each child is a | ||
| batch of small, mostly breaking fixes to one area, sized so one PR reviews in | ||
| one sitting. | ||
|
|
||
| ## Plan | ||
|
|
||
| Planned 2026-11-07 (maintainer, /quest-plan) from an audit of `release` | ||
| (a005c7ad9a) against `main` (a9d7925123) plus the open quests. Nine | ||
| read-only reviewers (net model, net session, transport, media formats, | ||
| native media, apps, JS core, browser media, bindings) scored 127 clusters | ||
| for performance, usability, testability, and future fit, using | ||
| `just api-diff` and consumer searches in this repository and its | ||
| downstream applications. The maintainer approved the plan as shown. The larger findings | ||
| became their own m1, m2, m3, and m4 quests; this epic holds the rest. | ||
|
|
||
| This audit ran while [moq-dev/moq#8088](https://github.com/moq-dev/moq/pull/8088), | ||
| the previous API audit's final pass, was open, and none of its children | ||
| repeats an item #8088 changes. A child that starts after #8088 merges | ||
| rechecks each item against `main` and drops what is already done. | ||
|
|
||
| Rules every child follows: | ||
|
|
||
| - Removal beats addition. A public item with no caller in this repository, | ||
| a known downstream application goes private, unless an m1 or m2 quest plans a | ||
| caller. | ||
| - No serde aliases, refusals, or shims for a spelling `release` never | ||
| shipped. | ||
| - Each child lists its public API and wire impact in its PR, and its Impact | ||
| section says how to migrate. | ||
|
|
||
| Rejected in planning: | ||
|
|
||
| - One audit PR for every area: each child touches a different owner's code, | ||
| and #8088 showed that a 100-file audit PR spends weeks rebasing. | ||
| - Folding these items into the larger quests: those wait on decisions or | ||
| prototypes, and these do not. | ||
|
|
||
| ## Required | ||
|
|
||
| - [moq-net's small surface fixes](/quest/m2/api-shape/net.md) - one spelling per session, admission, compression, and priority surface, and no public wire codes | ||
| - [Transports take shared types](/quest/m2/api-shape/transport.md) - moq-uring takes a congestion factory and rustls configs, and the tokio server request stops exposing its QUIC internals | ||
| - [Media crates' small surface fixes](/quest/m2/api-shape/media.md) - exporters, the container consumer, catalog color range, rate grant, moq-stats, JSON, and MSF each have one path and one name | ||
| - [Native media's small surface fixes](/quest/m2/api-shape/native.md) - audio encode internals go private, `on_demand` has one meaning, and video and render setters fold into their constructors | ||
| - [Apps' small surface fixes](/quest/m2/api-shape/apps.md) - the relay, gateways, moq-hls, moq-cli, and moq-boy drop dead or unreachable surface and gain role names | ||
| - [JS packages' small surface fixes](/quest/m2/api-shape/js.md) - track info, connection, qmux, watch, publish, ui, video, boy, and auth exports each have one path and one name | ||
| - [Bindings' small surface fixes](/quest/m2/api-shape/bindings.md) - Go's read cancel, JSON producer construction, and the Python wheel's test module |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # [M] Apps' small surface fixes | ||
|
|
||
| ## Goal | ||
|
|
||
| - moq-relay: | ||
| - `Internal::with_uring` becomes crate-private; it takes a type nobody | ||
| outside can build since `uring` went private. | ||
| - The hidden refusals for config keys and flags `release` never shipped | ||
| (`[session]`, `[peer]`, `--peer-*`, `--limits-*-requests`, | ||
| `auth.verifications`) are deleted. | ||
| - `cluster::Options.session` becomes `client`, matching its type and the | ||
| `[limits.client]` key. | ||
| - `Relay::{rtmp, webrtc}` become take-once `&mut self -> Option<_>`, like | ||
| `admissions()`. | ||
| - `session::View` and `shutdown::{Tally, Drained}` get | ||
| `#[non_exhaustive]`. | ||
| - moq-webrtc drops the dead `Error::{SessionNotFound, SessionClosed}` and | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Technical details# SessionClosed is live
## Affected sites
- quest/m2/api-shape/apps.md:17 — claims both variants are dead
- rs/moq-webrtc/src/session.rs:259 — constructs `Error::SessionClosed`
- rs/moq-webrtc/src/session.rs:577,584 — `end()` folds it into `Ok`
- rs/moq-webrtc/src/server/whip.rs:235, rs/moq-webrtc/src/server/whep.rs:230 — only `SessionNotFound` is matched
## Required outcome
- The item drops only `SessionNotFound`, or states the `session.rs` rework that stops constructing and folding `SessionClosed`. |
||
| hides `p2p` (`#[doc(hidden)]`, as on release) until the | ||
| [m4 p2p work](/quest/m4/p2p/README.md) has a caller. | ||
| - moq-srt's `dial` module becomes private; `Client` keeps one path. | ||
| - moq-hls gains `Error::is_denied()`, so embedders stop matching nested | ||
| errors. | ||
| - `moq export hls`'s listener flags become `--hls-listen` and | ||
| `--hls-tls-{cert,key,generate,root}`, matching the `MOQ_HLS_*` | ||
| environment, with named refusals for the old flags, which shipped. | ||
| - moq-boy's Rust crate stops exporting its internals (the JS half is in | ||
| [the JS child](/quest/m2/api-shape/js.md)). | ||
|
|
||
| ## Plan | ||
|
|
||
| Found by the 2026-11-07 API shape audit (apps); see the | ||
| [epic](/quest/m2/api-shape/README.md). Decided 2026-11-07 (maintainer): | ||
| ✅ hide `p2p` until m4 (rejected: keep it public; delete it). Gateway ingest | ||
| is [gateway-ingest](/quest/m2/gateway-ingest.md). Downstream code that | ||
| matches the deleted webrtc variants loses only dead arms. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # [S] Bindings' small surface fixes | ||
|
|
||
| ## Goal | ||
|
|
||
| - Go: a cancelled context on `Next`, `ReadFrame`, or `RecvGroup` cancels | ||
| only that read, as in Python, Swift, Kotlin, Dart, and C++. Today | ||
| `go/wrapper/subscribe.go` passes the consumer's `Cancel`, so a caller | ||
| cannot bound one read and continue. Range-loop iterators still cancel the | ||
| consumer when the loop exits. Check first that the Go generator fork | ||
| supports a per-call cancel. | ||
| - JSON tracks have one constructor shape in moq-ffi and every wrapper: a | ||
| producer the catalog advertises comes from the catalog producer, not from | ||
| a free constructor that the caller must then register. | ||
| - Python: `moq.testing` leaves the published wheel; tests import it from the | ||
| source tree. | ||
|
|
||
| ## Plan | ||
|
|
||
| Found by the 2026-11-07 API shape audit (bindings); see the | ||
| [epic](/quest/m2/api-shape/README.md). The generated check that each | ||
| hand-written wrapper exports every FFI item is | ||
| [binding-export-coverage](/quest/m4/binding-export-coverage.md). moq-c's | ||
| renames are in [moq-dev/moq#8060](https://github.com/moq-dev/moq/pull/8060). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # [M] JS packages' small surface fixes | ||
|
|
||
| ## Goal | ||
|
|
||
| - `@moq/net`: | ||
| - A resolved `Track.Info` uses `null` for "none" (`maxAge`, `timescale`); | ||
| `Track.infoDefaults` and the `Track.rescale` alias go. | ||
| - `Connection.Established` becomes `Session`, and the orphan | ||
| `Connection.Extensions` type goes. | ||
| - `readBool` goes; it has no caller and no Rust mirror. | ||
| - `RouteOptions.instance` takes `{ id, epoch }`, like Rust's | ||
| `with_instance(instance, epoch)`. | ||
| - `@moq/qmux` exports `Session` by name instead of an anonymous default. | ||
| - `@moq/watch`: the decoder and source plumbing outputs are `@internal`, the | ||
| renderer's output is a named `Video.RendererOutput`, and `<moq-watch>`'s | ||
| `player` property goes private, so each component has one path. | ||
| - `@moq/publish`: `Rendition.onDemand` becomes an enum, `Broadcast.join` | ||
| becomes a `Getter`, and the five internal source helpers are unexported. | ||
| - `@moq/ui` and `@moq/video` mark their helpers `@internal`; only `Support`, | ||
| `Report`, `Show`, `Level`, and `Status` stay public in `@moq/ui`, and | ||
| `rotateVideoDimensions`, `Dimensions`, `Presentation`, and | ||
| `Preview.Transcode` leave `@moq/video`'s public API. | ||
| - `@moq/boy` stops exporting `Game`, `GameConfig`, `KEY_MAP`, and its | ||
| `Moq` and `Watch` namespace re-exports, keeping the element and status | ||
| schemas. | ||
| - `@moq/auth`'s `Key.sign` takes one spelling for caps. | ||
|
|
||
| ## Plan | ||
|
|
||
| Found by the 2026-11-07 API shape audit (JS core and browser media); see | ||
| the [epic](/quest/m2/api-shape/README.md). Durations are | ||
| [js-time-types](/quest/m2/js-time-types.md); hosted assets and the | ||
| `supported` default are m1 quests. Each change updates its package's | ||
| `api/*.api.md`, and moq.dev's npm consumer is checked for each removed | ||
| export. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: moq-dev/moq
Length of output: 1986
Script executed:
Repository: moq-dev/moq
Length of output: 42483
Script executed:
Repository: moq-dev/moq
Length of output: 16202
Keep the getter change out of additive work.
If this quest lands after the cut, callers checking
publish.announce === undefinedwill no longer detect invalid attributes. Keep that getter behavior in m1, or move the breaking getter change to m2.