Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ explicit exception to the public model audit.
Added 2026-10-16: refresh, a breaking `Demand` change, so it lands before
the cut.

Added 2026-10-22 (maintainer, from an external API audit): small breaks
that would otherwise force another breaking release (the FFI encoder config,
FromStr, dead items, `SessionClosed`, unprefixed C++), the hang draft's
warmup rule for the shipping dual decoder, the binding migration guide fixes,
and the API-diff tooling. Public routes now wait on cluster routing.

Added 2026-10-20 (maintainer): the probe target, native probing, and the
native rung disable moved up from the [m2 probe epic](/quest/m2/probe/README.md),
so Rust, FFI, and OBS publishers recover a stopped rendition in this release;
Expand All @@ -69,6 +75,7 @@ lite-07 stream type here.
- [Rust request credit](/quest/m1/rs-request-credit.md) - a moq-net request fails at once without stream credit instead of waiting
- [Generated C bindings](/quest/m1/c/README.md) - C generated from moq-ffi ships as `moq-c` 0.8.0 and replaces the hand-written libmoq
- [Exact timestamps in every binding](/quest/m1/binding-timestamps.md) - bindings carry `{value, scale}` timestamps instead of lossy microseconds
- [Binding encoder config](/quest/m1/binding-encoder-config.md) - binding encoders take an exact rational framerate, and the publication track name moves to options only the producers take
- [moq-transport passthrough](/quest/m1/ietf-extension/README.md) - object IDs, properties, end status, datagram objects, and unknown track properties survive moq-transport -> moq-relay (and a relay cluster) -> moq-transport; moxygen's moq-test sections 1-7 pass nightly, except cases that use a subgroup other than 0
- [Refresh](/quest/m1/refresh/README.md) - a join asks for a fresh group once the current group's deltas exceed a publisher-advertised byte ratio, at every hop; replaces `Demand::used`/`unused` and moq-json's `delta_ratio`
- [Announcement takeover](/quest/m1/announce-takeover.md) - a new independent route explicitly continues instances served through its predecessor, with shared Rust/JS semantics and lite-07 wire
Expand Down Expand Up @@ -117,6 +124,12 @@ lite-07 stream type here.
- [moq-net internals](/quest/m1/net-internals.md) - no per-group session clones, no transport type parameter in lite and IETF internals, and the `Local` check measured
- [Main is no slower than release](/quest/m1/release-perf/README.md) - every benchmark where main is slower than release is fixed or accepted with a reason, checked by a final paired run before the cut
- [Subscribe update churn](/quest/m1/subscribe-update-churn.md) - a viewer sends SUBSCRIBE_UPDATE only on a meaningful change, measured after the publisher stall fix
- [Unprefixed C++ free functions](/quest/m1/cpp-free-function-prefix.md) - generated free functions drop `moq_`, and `moq.hpp` deletes its five pass-through wrappers before C++ first publishes
- [Error cleanups](/quest/m1/error-cleanups.md) - delete the unused `Error::SessionClosed`; raw transport failures already map to `Unroutable`
- [FromStr parsers](/quest/m1/from-str-trait.md) - hang, moq-auth, and moq-msf implement `FromStr` instead of inherent `from_str`
- [Drop dead items](/quest/m1/drop-dead-items.md) - the audit's uncalled public items and test helpers are removed
- [Warmup in the hang draft](/quest/m1/warmup-draft.md) - the draft lets a dual-decoder consumer present before `warmup`, matching the shipping `decode::Consumer`
- [API-diff check](/quest/m1/api-diff.md) - a recipe diffs every published package's API against its last release, run on PRs into release and against main before the cut
- [Interop coverage](/quest/m1/interop-coverage/README.md) - the riskiest moq-transport features moq-net exposes get cross-implementation tests over the even drafts 14 to 22
- [Runner nightly](/quest/m1/interop-runner-nightly.md) - a nightly job runs the upstream interop runner against our relay and clients, so newly registered implementations with a published image are tested without a change here
- [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
Expand Down
2 changes: 1 addition & 1 deletion quest/m1/api-audit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,5 @@ Rejected in planning:

- [Claim request type](/quest/m1/public-model/claim-request-type.md) - removes `accept` from application requests; [the origin announces](/quest/m1/api-audit/announce-owner.md) narrows `Prepared` beside it
- [Readers follow restarts](/quest/m1/sink-restart-follow.md) - moves readers onto the follow operation that [two broadcast resolutions](/quest/m1/api-audit/resolve.md) names
- [API-diff check on release PRs](/quest/m2/release/migrate-audit.md) - the backstop that catches breaks this epic misses
- [API-diff check on release PRs](/quest/m1/api-diff.md) - the backstop that catches breaks this epic misses
- [Main is no slower than release](/quest/m1/release-perf/README.md) - the other release-readiness check
3 changes: 3 additions & 0 deletions quest/m1/api-audit/migrate.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Decided 2026-10-22 (API audit). Known gaps, verify each against
- Bindings: merge the contradictory `finish` entries ("removed (#4152)" and
"the new `finish` lets go (#6157)") into one: `finish()` now returns a
linger handle; call `close()` for the old behavior.
- Bindings: `rs/moq-ffi/MIGRATE.md` says a raw track is timed by default,
but `MoqTrackInfo.timescale` defaults to `None` (untimed) while release
defaulted to microseconds; the net change is timed to untimed by default.
- Bindings: `MoqAudioInit.track` and `MoqVideoInit.track` moved to
`MoqMediaTarget::Named`, with no entry.
- `cpp/moq/MIGRATE.md`: about 130 lines for a package never released; empty
Expand Down
44 changes: 44 additions & 0 deletions quest/m1/api-diff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# [L] API-diff check on release PRs

## Goal

A `just` recipe diffs each published package's public API against its last
published version, and every PR into `release` runs it. A backport fails on
any break; the breaking cut PR reports the diff for the
[migration audit](/quest/m2/release/migrate-audit.md).

## Plan

Decided 2026-10-16 (maintainer interview), split out of the migration audit
and moved to m1 on 2026-10-22 (maintainer, from an external API audit) so
the report runs locally against `main` while m1's breaks are still landing,
instead of first appearing at the cut:

- Commit `!` markers undercount: a 2026-10-16 sample estimated 12-15
unmarked breaks on top of 87 marked ones, a floor since signature-only
changes escape the heuristic. This check is the backstop; PRs into `main`
get no CI check.
- Runs on PRs into `release` only: backports must keep the published API
(CONTRIBUTING), and the cut PR gets a full audit.
- Backports fail on any detected break. The cut PR only reports: Rust
versions are bumped by release-plz after the cut lands, so the diff cannot
gate on a version bump there.
- One `just` recipe, three backends: cargo-semver-checks for Rust crates,
emitted `.d.ts` API reports for `@moq/*` packages, and a `moq.h` plus
UniFFI interface diff for the bindings. Prefer maintained tools over
hand-rolled diffing. Wire it into the workflow that runs on PRs into
`release`.
- Baseline is the last published artifact, not a git tag: `@moq/*` and
`moq-rs` publish without tags. Rust compares against crates.io
(cargo-semver-checks' default), JS against the npm tarball's declarations,
and the FFI interfaces against the published `moq-ffi` crate and the last
released C archive's `moq.h`.
- Coverage: the report covers Rust crates, `@moq/*` declarations, and the
generated FFI interfaces. A break only in a hand-written binding wrapper
(`py/moq-rs`, `kt/moq`, `dart/moq`, `go/wrapper`, `swift`, `cpp/moq`,
`cpp/obs`) or a binary's flags, env vars, or config keys escapes it; the
migration audit reads those by hand. Per-language wrapper checks are out
of scope until a missed break shows they are needed.

Run it against `main` when it lands and put the unmarked breaks it finds in
the PR description, so their `MIGRATE.md` entries land before the cut.
41 changes: 41 additions & 0 deletions quest/m1/binding-encoder-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# [M] Binding encoders take exact rates and codec-only settings

## Goal

A binding caller can encode 30000/1001 video exactly, and a codec-only
encoder accepts nothing it ignores. `MoqVideoEncoderInput.framerate` becomes
a rational rate instead of a `u32` the encoders turn into `Rate(n, 1)`, and
the publication `track` name leaves `MoqVideoEncoderOutput` and
`MoqAudioEncoderOutput` for options only `MoqVideoProducer::new` and
`MoqAudioProducer::new` take.

## Plan

Decided 2026-10-22 (maintainer, from an external API audit): one quest for
both, since they break the same records and every wrapper, so callers
migrate once with the cut.

- Rate: `rs/moq-ffi/src/video.rs` builds `moq_video::Rate::new(framerate, 1)`
in `video_encoder_config` (the codec-only `MoqVideoEncoder`) and again
inline in `MoqVideoProducer::new`; `moq_video::Rate` already holds a
numerator and denominator. Expose it as a numerator/denominator record and
build the rate once. Audio's integer `sample_rate` is exact and stays.
- Publication options: `track` is the only publish-only field today.
`video_encoder_config` and `audio_settings` never read it. Nest it in a
publication options record taken by the producers, beside the existing
`catalog` and `bandwidth` arguments, rather than adding a fourth argument.
Comment on lines +24 to +26

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for the constructors' existing fourth argument

When this quest is implemented, both MoqVideoProducer::new and MoqAudioProducer::new already take four arguments: catalog, input, output, and bandwidth. Placing a new publication-options record beside the existing catalog and bandwidth arguments would therefore create a fifth argument, despite the plan claiming this avoids adding a fourth. Clarify which existing arguments the record absorbs so the planned API can satisfy the repository's argument-count rule.

AGENTS.md reference: AGENTS.md:L68-L69

Useful? React with 👍 / 👎.

Keep the `audio`/`video` namespaces. Propose the record and field names
with a recommendation in the PR before shipping them.
- Wrappers alias the uniffi records, so update `py/moq-rs`, `kt/moq`,
`swift`, `dart/moq`, `go/wrapper`, `cpp/moq`, their tests and `doc/lib/*`
per the Cross-Package Sync table. The generated C picks the records up;
the hand-written `rs/moq-c` has no raw encoder, so it is untouched.
- [OBS moq-video adapter](/quest/m2/obs-moq-video/adapter.md) later adds a
preset to the codec-only config; this shape is the one it extends.

Public API: breaking in moq-ffi and every binding wrapper, each with a
`MIGRATE.md` entry. Wire: none.
Comment on lines +36 to +37

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude the unpublished C++ wrapper from migration entries

Because this quest explicitly includes cpp/moq among the wrappers, requiring a MIGRATE.md entry for every wrapper directs the implementer to add a C++ migration that never occurred for users. The same commit's quest/m1/api-audit/migrate.md says to empty that file because the package has never been released, and cpp-free-function-prefix.md likewise says it needs no upgrade note. Exempt unpublished wrappers here so the quests do not impose contradictory completion criteria.

Useful? React with 👍 / 👎.


## Related

- [Exact timestamps in every binding](/quest/m1/binding-timestamps.md) - the other exact-time break to the same bindings in this cut
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ types already drop `Moq` (`strip_type_prefix` in `cpp/moq/uniffi.toml`), so
## Plan

Decided with the maintainer on 2026-10-17: the goal as drafted, the follow-up
#5727 deferred.
#5727 deferred. Moved to m1 on 2026-10-22 (maintainer, from an external API
audit): the C++ package is unpublished, so stripping the prefix before its
first publication avoids shipping both the `moq::moq_*` names and their
wrappers.

The option belongs in the uniffi-bindgen-cpp fork, released and pinned the
way #5727 pinned `strip_type_prefix` (every place that PR moved the pin).
Expand Down
5 changes: 4 additions & 1 deletion quest/m2/drop-dead-items.md → quest/m1/drop-dead-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ since [#5678](https://github.com/moq-dev/moq/pull/5678).
## Plan

From [moq-dev/moq#6166](https://github.com/moq-dev/moq/pull/6166). Decided
2026-10-21 with the maintainer: m2. Verify each still has no caller across
2026-10-21 with the maintainer: m2.
Moved to m1 on 2026-10-22 (maintainer, from an external API audit): the
cut is breaking anyway, so this break ships with it instead of forcing
another breaking release later. Verify each still has no caller across
the repo, bindings included, before removing it; keep any that gained one.
The test helper lives in `model/track.rs`, which many open PRs churn, so
expect merge conflicts there.
Expand Down
8 changes: 8 additions & 0 deletions quest/m2/error-cleanups.md → quest/m1/error-cleanups.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ deleted.

## Plan

Moved to m1 on 2026-10-22 (maintainer, from an external API audit): the
cut is breaking anyway, so this break ships with it instead of forcing
another breaking release later.

Decided with the maintainer on 2026-10-17: the goal as drafted, from the
follow-ups of [#5729](https://github.com/moq-dev/moq/pull/5729), widened the
same day to Rust after review found Rust sends `Internal` too.
Expand All @@ -24,3 +28,7 @@ decided 2026-10-22 (maintainer): keep the removal and construct
`StreamError::Session(SessionError::Cancel)` there directly. Removing a
public variant is a breaking Rust change: add the `rs/moq-net/MIGRATE.md`
entry. Wire: none.

## Related

- [One clean close](/quest/m1/api-audit/clean-close.md) - collapses the clean session-close spellings this removal touches
5 changes: 4 additions & 1 deletion quest/m2/from-str-trait.md → quest/m1/from-str-trait.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ inherent `pub fn from_str`, so `str::parse` works and the
From the lint audit in
[moq-dev/moq#6159](https://github.com/moq-dev/moq/pull/6159), which kept the
inherent methods because the switch breaks callers. Decided 2026-10-21 with
the maintainer: do it in m2. Today's inherent methods are in
the maintainer: do it in m2.
Moved to m1 on 2026-10-22 (maintainer, from an external API audit): the
cut is breaking anyway, so this break ships with it instead of forcing
another breaking release later. Today's inherent methods are in
`rs/hang/src/catalog/root.rs`, `rs/moq-auth/src/key.rs`,
`rs/moq-auth/src/set.rs`, and `rs/moq-msf/src/lib.rs`; check for more.
Remove the inherent method rather than keeping it beside the trait.
Expand Down
5 changes: 3 additions & 2 deletions quest/m1/public-model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Inventory on `main` at b4eab0db1:
only inside `model/`.
- The 106 split into ingest (landed in [moq-dev/moq#6111](https://github.com/moq-dev/moq/pull/6111)),
[serving](/quest/m1/public-model/serve.md),
[routes and answering](/quest/m1/public-model/answer.md), and the
[answering](/quest/m1/public-model/answer.md) (with [routes](/quest/m1/public-model/routes.md) split out later), and the
passthrough carve-out (listed in each child where it shares a type).
- The 16 test-only items (`group::Info::produce`, `group::Producer::is_aborted`
and `is_finished`, `track::Info::timed`, `track::Producer::new`,
Expand Down Expand Up @@ -104,7 +104,8 @@ Work owned by this README, after the children land:

- [Claim request type](/quest/m1/public-model/claim-request-type.md) - accepting an application claim's request fails to compile instead of panicking
- [Public serving](/quest/m1/public-model/serve.md) - a custom publisher reads a track's start, cursor, and group expiry for its wire through public calls
- [Public routes and answering](/quest/m1/public-model/answer.md) - a custom relay ingests routes, answers broadcast and track requests on demand, and advertises without echoing a peer's routes back
- [Public answering](/quest/m1/public-model/answer.md) - a custom relay answers broadcast and track requests on demand and closes them once unused
- [Public routes](/quest/m1/public-model/routes.md) - a custom relay ingests routes under a peer's identity and advertises without echoing them back, once cluster routing lands
- [Public model after ranges, handover, and the JS tail](/quest/m1/public-model/deferred.md) - fetch and track-info answering, the cache peeks, JS `fork`/`mirror`, and JS `endTrack`, once the quests that reshape them land

## Related
Expand Down
Loading
Loading