Repository navigation
quest: plan the release audit's unowned follow-ups #6342
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,33 @@ | ||
| # [S] The HLS segment cursor reports a failed timeline | ||
|
|
||
| ## Goal | ||
|
|
||
| `moq-hls`'s export `segments::Consumer::next` drains the segments a failed | ||
| timeline still covers, then returns the failure as an error. `Ok(None)` | ||
| means only a clean end, so a recorder that mirrors a broadcast to storage | ||
| can't take a truncated recording for a complete one. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-22 (maintainer, from the release audit): fix it before the | ||
| cut, since changing what `Ok(None)` means is a breaking change. | ||
| [moq-dev/moq#6153](https://github.com/moq-dev/moq/pull/6153) fixed the | ||
| playlist side and named this follow-up. | ||
|
|
||
| In `rs/moq-hls/src/export/segments.rs`, `Consumer::next` returns `Ok(None)` | ||
| when `rendition.is_failed(&row)`, and its doc comment says so. A shared | ||
| reference failure ends the same way: `Producer::fail` records `failed` | ||
| without setting `ended`, the closed window maps to `Ready(None)`, and | ||
| `next_after` never reads `failed`. `Producer::failure()` holds the error | ||
| nobody reads. | ||
|
|
||
| Return the window's or rendition's failure once the covered segments drain. | ||
| Fix the doc comment and add a `rs/moq-hls/MIGRATE.md` entry. Test the | ||
| cursor alongside the playlist for both failure sources: valid segments | ||
| first, then the error, never `Ok(None)`. | ||
|
|
||
| The cursor has no consumer outside its tests yet. It stays public because | ||
| it is the documented entry point for mirroring to storage. | ||
|
|
||
| Public API: `segments::Consumer::next` returns an error where it returned | ||
| `Ok(None)` (breaking). Wire: none. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # [S] JS release refuses a package whose @moq dependency is missing | ||
|
|
||
| ## Goal | ||
|
|
||
| `js/common/release.ts` refuses to publish a package to npm when any | ||
| `@moq/*` dependency range in its built `package.json` resolves to no | ||
| published version, and names the missing ones. A failed dependency publish | ||
| can no longer leave a dependent on npm that fails to install. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-22 (maintainer, from the release audit): requested as a | ||
| follow-up by [moq-dev/moq#6243](https://github.com/moq-dev/moq/pull/6243). | ||
|
|
||
| `release-js.yml` runs `bun --filter '*' release`, which orders packages by | ||
| dependency but still runs dependents after a dependency's script fails. | ||
| `release.ts` skips a version already on npm and otherwise publishes; its only | ||
| `@moq/*` existence check gates the JSR dry run. `js/common/package.ts` | ||
| rewrites `workspace:^` to `^<version>` without checking npm. | ||
|
|
||
| Before `npm publish`, read the dependencies and peer dependencies of | ||
| `dist/package.json`, run `npm view <name>@<range> version` for each `@moq/*` | ||
| entry, and exit non-zero listing every range with no match. Reuse the | ||
| existing JSR dry-run lookup instead of adding a second one. Confirm that | ||
| `deno publish` already refuses an unresolvable `jsr:` import; extend the | ||
| check to JSR only if it does not. | ||
|
|
||
| Prove it on a dry run that depends on an unpublished `@moq/*` version: the | ||
| run fails, naming the package and range. | ||
|
|
||
| Public API: none. Wire: none. | ||
|
|
||
| ## Related | ||
|
|
||
| - [First npm publish](/quest/m2/release/npm-first-publish.md) - the one-time hand publish of the new names this check would otherwise refuse |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # [S] qmux aborts and closes without the peer's help | ||
|
|
||
| ## Goal | ||
|
|
||
| In the in-tree `@moq/qmux` (`js/qmux`), `writer.abort()` on a stream whose | ||
| write is waiting for stream or connection send credit rejects that write and | ||
| sends RESET_STREAM at once. `close()` closes the socket only after | ||
| APPLICATION_CLOSE is handed to it, or after a bounded stall: a backed-up | ||
| WebSocket that drains in time delivers the frame, and one still wedged at the | ||
| deadline closes without it. Neither outcome waits for the peer to grant | ||
| credit, and close never relies on a fixed delay. Rust | ||
| `rs/qmux` already behaves this way and is out of scope. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-22 (maintainer, from the release audit): one quest for both, | ||
| since both live in `js/qmux/src/session.ts` and share one contract: local | ||
| lifecycle never depends on peer cooperation. Both were deferred by | ||
| [moq-dev/moq#6124](https://github.com/moq-dev/moq/pull/6124). | ||
|
|
||
| Abort: the sink's `write` reaches `#claimSendCredit`, which awaits | ||
| `flow.sendCredit.claim()` and `#connCredit.claim(1n)`. `Credit.claim` in | ||
| `js/qmux/src/credit.ts` takes no signal, and WritableStream runs the sink's | ||
| `abort` only after the in-flight write settles, so the abort waits for credit. | ||
| Give `Credit.claim` an `AbortSignal` that removes its waiter and rejects, and | ||
| pass the sink controller's `signal` down through the stream data path, so the | ||
| existing abort handler sends RESET_STREAM immediately. | ||
|
|
||
| Close: `close()` and `#sendConnectionClose` queue APPLICATION_CLOSE, then | ||
| `sleep(100ms)` before `#transportClose()`. The scheduler holds the frame until | ||
| `sink.ready()`, and the WebSocket ponyfill holds a write while | ||
| `bufferedAmount` is high, so a backed-up socket closes with the frame never | ||
| sent. Replace both sleeps with a promise the scheduler resolves once the | ||
| control lane has flushed. Drop queued stream frames first, so | ||
| APPLICATION_CLOSE goes out next. Bound the wait like Rust's `CLOSE_TIMEOUT` | ||
| (`rs/qmux/src/session.rs`), started only while the writer is stalled. | ||
|
|
||
| Test with the controlled clock and a wedged socket: an abort blocked on each | ||
| credit kind emits RESET_STREAM with no peer grant; a close behind a socket | ||
| that drains before the deadline writes APPLICATION_CLOSE before the transport | ||
| closes; and one that never drains closes at the deadline without it. | ||
|
|
||
| Public API: none. Wire: none. | ||
|
|
||
| ## Related | ||
|
|
||
| - [qmux no-wait opens](/quest/m1/qmux-no-wait.md) - another fix in the same file; its PR is [moq-dev/moq#6271](https://github.com/moq-dev/moq/pull/6271) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # [S] The draft 14-16 adapter keeps session errors | ||
|
|
||
| ## Goal | ||
|
|
||
| On moq-transport drafts 14 to 16, a session-level transport error from | ||
| `ControlStreamAdapter` reaches the session with its cause instead of as | ||
| `Closed`. A peer that ends the session with a terminal error, such as | ||
| ProtocolViolation or Unauthorized, is not redialed as if the drop were | ||
| transient. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-22 (maintainer, from the release audit): m2. The race is | ||
| narrow and limited to the older drafts. It is the session-scope follow-up | ||
| left by [moq-dev/moq#6251](https://github.com/moq-dev/moq/pull/6251), which | ||
| kept stream errors through `AdapterError::Real`. | ||
|
|
||
| In `rs/moq-net/src/ietf/adapter.rs`, the adapter's `Session` impl maps the | ||
| native `poll_accept_bi`, `poll_open_uni`, `poll_accept_uni`, the datagram | ||
| send and receive, and `poll_closed` errors to `Error::Closed`. In | ||
| `ietf/session.rs`, `adapter_run` reads the real SETUP stream first and usually | ||
| keeps the peer's code. The code is lost when a unis, dispatch, or datagram | ||
| future fails first. The session then reports `Closed`, and | ||
| `moq-tokio`'s `is_terminal` treats that as retryable. | ||
|
|
||
| Carry the transport error through the way `AdapterError::Real` does, mapped | ||
| with the negotiated registry. Reproduce first: a draft-14 peer closes with | ||
| ProtocolViolation while a uni or datagram poll is pending, and the client | ||
| must see a terminal error and not redial. | ||
|
|
||
| Public API: none. Wire: none. | ||
|
|
||
| ## Related | ||
|
|
||
| - [moq-net compiles once](/quest/m1/net-erase-transport.md) - its open PR [moq-dev/moq#6176](https://github.com/moq-dev/moq/pull/6176) touches the same adapter |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # [S] moqsrc plays surround Opus | ||
|
|
||
| ## Goal | ||
|
|
||
| `moqsrc` outputs `audio/x-opus` caps that `opusdec` accepts for a 3 to 8 | ||
| channel Opus rendition, so surround Opus published through `moqsink` plays | ||
| back through GStreamer. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-22 (maintainer, from the release audit): m2. Receive never | ||
| worked, so this is not a regression. | ||
| [moq-dev/moq#4991](https://github.com/moq-dev/moq/pull/4991) fixed publishing | ||
| and named this follow-up. | ||
|
|
||
| `rs/moq-gst/src/source/imp.rs` builds the caps from rate and channels, plus | ||
| `codec_data` and `stream-format=ogg` when a description exists. `opusdec` | ||
| ignores `codec_data` and reads `streamheader` or the mapping fields, so with | ||
| more than two channels it assumes family 0 and refuses. | ||
|
|
||
| Parse the catalog's OpusHead description with the existing `opus::Mapping` | ||
| and set `channel-mapping-family`, `stream-count`, `coupled-count`, and | ||
| `channel-mapping`. This needs no synthesized OpusTags, unlike a | ||
| `streamheader`. Test `opusenc` 5.1 through `moqsink`, a relay, `moqsrc`, and | ||
| `opusdec`, checking six decoded channels. The only moqsrc test rendition | ||
| today is stereo. | ||
|
|
||
| Public API: none. Wire: none. | ||
|
|
||
| ## Related | ||
|
|
||
| - [CMAF surround Opus](/quest/m2/cmaf-opus-surround.md) - the same mapping table through fMP4 `dOps`, independent of this caps path |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ production stability proven merely because upstream artifacts published. | |
| - [API-diff check](/quest/m2/release/migrate-audit.md) - PRs into release diff the public API; backports refuse breaks, the cut confirms MIGRATE.md coverage | ||
| - [API shape review](/quest/m2/release/api-review.md) - every new or changed public API reviewed for a better shape before the cut | ||
| - [Feature review](/quest/m2/release/feature-review.md) - every major work line since the last release judged end to end before the cut | ||
| - [Claim new npm names](/quest/m2/release/npm-first-publish.md) - a maintainer claims `@moq/clock`, `libav`, `video`, and `p2p` on npm and JSR with trusted publishing, before the cut publishes them | ||
|
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.
This prerequisite is scheduled under release execution, which starts only after m1, but the m1 preflight is intended to fail dry runs while an AGENTS.md reference: AGENTS.md:L28-L28 Useful? React with 👍 / 👎. |
||
| - [Cut and publish](/quest/m2/release/cut.md) - independently executable after m1; release-triggered publication | ||
| - [Published assets](/quest/m2/release/assets-release.md) - npm carries hostable worklets | ||
| - [C++ publication](/quest/m2/release/cpp-release.md) - archives and matching OBS plugin publish and install | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # [XS] Claim the new @moq npm and JSR names | ||
|
|
||
| ## Goal | ||
|
|
||
| `@moq/clock`, `@moq/libav`, `@moq/video`, and `@moq/p2p` exist on npm, and | ||
| the three with JSR packages exist on JSR, each with trusted publishing | ||
| attached to `moq-dev/moq`. The cut's release workflow can then publish | ||
| their real versions. A maintainer does this by hand. Delete this quest once | ||
| the checks pass: | ||
|
|
||
| - `npm view @moq/<name>` resolves for all four, and the package settings show | ||
| the `moq-dev/moq` trusted publisher. | ||
| - `https://api.jsr.io/scopes/moq/packages/<name>` returns 200 for `clock`, | ||
| `video`, and `p2p`, each linked to the repository. `@moq/libav` sets | ||
| `"jsr": false`. | ||
|
|
||
| ## Plan | ||
|
|
||
| Found 2026-10-22 while planning the release audit's follow-ups: all four | ||
| names return 404, and nearly every published package (net, hang, watch, | ||
| publish, auth, signals, and more) now depends on `@moq/clock`. npm trusted | ||
| publishing attaches only to an existing package, so without this the cut's | ||
| publish fails on these names and still publishes dependents that can't | ||
| install. [moq-dev/moq#6243](https://github.com/moq-dev/moq/pull/6243) raised | ||
| it for `@moq/libav` alone. | ||
|
|
||
| Decided 2026-10-22 (maintainer): publish a minimal `0.0.0` placeholder | ||
| (README only) per name to claim it, then attach the trusted publisher. The | ||
| cut publishes the real `0.1.0` through the workflow with provenance, so no | ||
| real version is published by hand. `release.ts` compares against the | ||
| `latest` tag, so the placeholder does not suppress that publish. | ||
|
|
||
| Until the cut publishes `@moq/libav` 0.1.0, Windows `bun install` keeps | ||
| failing, since `js/libav/build.ts` there unpacks the published tarball of | ||
| the workspace version. The placeholder does not change that. | ||
|
|
||
| Public API: none. Wire: none. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Release preflight](/quest/m1/js-publish-preflight.md) - refuses a dependent whose `@moq/*` dependency did not publish | ||
| - [Dart publication](/quest/m2/release/dart-publish.md) - the same trusted-publishing check for pub.dev |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # [XS] Half and quarter rate AC-3 | ||
|
|
||
| ## Goal | ||
|
|
||
| `moq-mux` parses AC-3 with bsid 9 and 10, the half and quarter sample-rate | ||
| variants, through TS and FLV import and TS export, instead of refusing them. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-22 (maintainer, from the release audit): support them rather | ||
| than only documenting the refusal. It is cheap and removes an inconsistency | ||
| noted in [moq-dev/moq#5758](https://github.com/moq-dev/moq/pull/5758): | ||
| `ac3_core` in `rs/moq-mux/src/ts/export.rs` counts bsid up to 10 as an AC-3 | ||
| core, then hands it to `ac3::parse_header`, which refuses anything above 8. | ||
|
|
||
| In `rs/moq-mux/src/codec/ac3.rs`, keep the frame-size tables and shift the | ||
| sample rate right by `bsid - 8`. Add a bsid 9 or 10 fixture through TS import | ||
| and TS export. Broadcast specs require 48 kHz, so these streams are rare, and | ||
| this stays low priority. | ||
|
|
||
| Public API: none. Wire: none. |
Uh oh!
There was an error while loading. Please reload this page.