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
33 changes: 16 additions & 17 deletions quest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,27 @@ grouped into milestones ordered by priority.

## Plan

m0 contains the immediate media work: the Pronto desktop GPU path and the four
0.0.x media crate API gates before 0.1. m1 is the dev branch line. m2 is the
next agent
wave across reliability, features, performance, and planning. Unsettled
quests may stay in m2 for planning; their implementation waits for the
required decisions. m3 holds later features, design studies, experiments,
and hardware validation. m4 is deferred: work whose first step is outside
this repository. Priority is separate from branch targeting:
published API breaks still target dev under the repository rules. An issue
already fixed on dev stays open until dev merges.
m0 contains the immediate priorities: the release API gates for the archive,
E2EE, socket, uring, and media packages, plus the Pronto desktop GPU path. m1
is the dev branch line. m2 is the next agent wave across reliability, features,
performance, and planning. Unsettled quests may stay in m2 for planning; their
implementation waits for the required decisions. m3 holds later features,
design studies, experiments, and hardware validation. m4 is deferred: work
whose first step is outside this repository. Priority is separate from branch
targeting: published API breaks still target dev under the repository rules. An
issue already fixed on dev stays open until dev merges.

The 2026-09 audit keeps uring-TCP in m2 and defers catalog identity, mobile
ownership and dependent capture, Linux OBS GPU feasibility, the LiveKit
shim, and experimental QUIC probing. Independently useful binding, codec,
room, and transport work stays in m2. The 2026-09-19 transport grooming
settled one QUIC stack (a moq-dev fork of noq), moved capacity probing back
into m2, and opened m4 for the hardware- and partner-gated quests.
ownership and dependent capture, Linux OBS GPU feasibility, the LiveKit shim,
and experimental QUIC probing. Independently useful binding, codec, room, and
transport work stays in m2. The 2026-09-19 transport grooming settled one QUIC
stack (a moq-dev fork of noq), moved capacity probing back into m2, and opened
m4 for the hardware- and partner-gated quests.

## Quests

- [m0: immediate media](/quest/m0/README.md) - Pronto GPU delivery and the
audio, video, transcode, and NVENC contracts required before 0.1
- [m0: immediate priorities](/quest/m0/README.md) - release API gates and the
reusable Pronto GPU path
- [m1: the dev line](/quest/m1/README.md) - the breaking API and wire
changes, the merge gates, and the merge itself
- [m2: next wave](/quest/m2/README.md) - implementation and planning across
Expand Down
97 changes: 63 additions & 34 deletions quest/m0/README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,50 @@
# m0: immediate media
# m0: immediate priorities

## Goal

Settle the public contracts of `moq-audio`, `moq-video`, `moq-transcode`, and
`moq-nvenc` before their first 0.1 releases, while supplying the reusable GPU
media support needed to remove raw-pixel CPU transfers from the Pronto CARLA
demo on its Linux/NVIDIA desktop. Product integration and installation live in
moq.pro.
Settle the public contracts of `moq-archive`, `moq-e2ee`, `moq-sock`,
`moq-uring`, `moq-audio`, `moq-video`, `moq-transcode`, and `moq-nvenc`
before the imminent release, while supplying the reusable GPU media support
needed to remove raw-pixel CPU transfers from the Pronto CARLA demo. These are
independent immediate tracks rather than mutual prerequisites.

## Plan

The Pronto GPU quests remain an independent deliverable within m0. They define
portable Vulkan/CUDA ownership, safe partial NVENC initialization, and a strict
GPU conversion path without changing the scope of the pre-0.1 API audit.

The four audited crates are 0.0.x, so their changes target main. Adapt callers
in other packages without breaking their published APIs, C layouts, or wire
formats. Do not bump versions as part of these quests. The final review records
when the four crates are ready for a separately requested release.

The package boundaries are explicit:
The archive, E2EE, socket, and uring crates are 0.0.1 on main after the dev
merge. Their six API quests gate the release and target main under the 0.0.x
exception. Inspect transitive public exposure before changing a shared symbol:
`moq-tokio` publicly re-exports `moq-sock`'s bind module. Keep that re-export
and its current names.

Keep the useful boundaries: archive owns storage and codecs, E2EE owns
protection rather than catalogs, sock owns runtime-neutral sockets, and uring
owns the local worker and its I/O. Prefer standard Rust ranges to a new public
range type. Keep uring's root `Config` reachable, since worker is private;
renaming `TxBuf` or moving bind names does not improve an ownership contract.

Their package boundaries are explicit:

- `moq-archive` replaces reversed integer-pair bounds with validated finite
`RangeInclusive<u64>` values, unifies streaming and paginated listing under
archive-owned query/entry types, and hides path helpers that are not consumer
APIs. Persisted object paths and bytes remain unchanged.
- `moq-e2ee` replaces raw/profile-global construction with application-owned
secrets and epoch-scoped `Credential`, `Generation`, `Epoch`, and track/group
handles. Raw crypto, catalog policy, retransmission internals, and the global
`Publication` registry leave the public surface.
- `moq-sock` makes incomplete reuseport groups unservable and retains every
member socket for the served group's lifetime.
- `moq-uring` derives worker and steering identity from owned sockets and
connections instead of independently supplied handles or shard values.
- Published `moq-tokio` keeps its worker signatures and `bind` re-export while
adapting internal plumbing. Its root names do not move.

The media crates are also 0.0.x, so their changes target main. Adapt callers in
other packages without breaking their published APIs, C layouts, or wire
formats. Do not bump versions as part of these quests. The media review records
when the four crates are ready for a separately requested 0.1 release.

Their package boundaries are explicit:

- `moq-audio` owns the PCM/layout and codec configuration split, decoder entry
point, publication authority, FEC removal, AEC attachment, playback outcome,
Expand All @@ -35,36 +60,40 @@ The package boundaries are explicit:
`moq-ffi`, `libmoq`, and language-binding signatures, layouts, and sentinel
behavior remain unchanged while their internals adapt.

The agreed direction is small, honest APIs: typed PCM layouts, rational video
rates, extensible GOP and frame records, explicit ownership, and no knobs that
claim behavior they do not provide. Synchronous codecs remain public and
The agreed media direction is small, honest APIs: typed PCM layouts, rational
video rates, extensible GOP and frame records, explicit ownership, and no knobs
that claim behavior they do not provide. Synchronous codecs remain public and
thread-confined; async sinks own codec execution. Native versus CPU output is a
choice, not a promise that every native backend yields a GPU surface.
choice, not a promise that every native backend yields a GPU surface. OpenH264
becomes optional but stays enabled by default. Rendering becomes opt-in;
inexpensive native codec defaults remain.

OpenH264 becomes optional but stays enabled by default. Rendering becomes
opt-in; inexpensive native codec defaults remain. Hardware libraries already
loaded at runtime do not need a toolkit dependency added to the build.

Each quest updates the existing crate documentation, examples, and affected
callers with its change. Contract tests run in CI; feature checks exercise each
crate independently, since workspace feature unification hides missing gates.
Cross-platform compilation and hardware execution are separate evidence.
The Pronto GPU quests remain an independent deliverable within m0. They define
portable Vulkan/CUDA ownership, safe partial NVENC initialization, and a strict
GPU conversion path without changing either API audit. Product integration and
installation live in moq.pro.

The audit was source inspection at `b2ef453e67`, not fresh compilation or
benchmarking. All public module families and their in-tree consumers were
reviewed; the generated NVIDIA ABI was inspected only where wrapper safety
depended on it. Performance concerns remain hypotheses until measured.
Each implementation updates its existing README, examples, and affected docs
inline and adds regression coverage to normal or nightly CI. Feature checks
exercise each media crate independently, since workspace feature unification
hides missing gates. Cross-platform compilation and hardware execution are
separate evidence. The audits were source-based, not a cryptographic review,
fresh compilation, benchmark, or Linux runtime validation.

API-preserving implementation, codec additions, allocation work, and hardware
proof remain in the existing backlog. Keep audio's integrated packetizing
Producer and transcode's validated Ladder and coalescing active cursor. Keep
one video Frame/Surface hierarchy and its deliberate native/wgpu type interop;
do not add another media abstraction or a renderer crate during stabilization.
Preserve the documented ability to abort publication after finish unless an
actual ownership fix requires a replacement error-finalization contract.

## Quests

- [E2EE path](/quest/m0/e2ee-path.md) - align the unpublished path derivation and vectors before the core adopts them
- [E2EE API](/quest/m0/e2ee-api.md) - epoch-scoped ownership replaces raw crypto, catalog helpers, and process-global claims
- [Socket group](/quest/m0/sock-group.md) - complete formation and retained sockets precede usable serving handles
- [uring identity](/quest/m0/uring-identity.md) - sockets and connections carry their worker and steering identity
- [Archive ranges](/quest/m0/archive-ranges.md) - one finite inclusive range convention replaces reversed integer pairs
- [Archive listing](/quest/m0/archive-listing.md) - one recording-scoped query exposes only supported listing behavior
- [Vulkan/CUDA surfaces](/quest/m0/video-vulkan-cuda.md) - retain producer slots
and synchronize GPU access safely across Vulkan and CUDA
- [NVENC registration rollback](/quest/m0/nvenc-registration.md) - release resources when mapping fails after registration
Expand Down
40 changes: 40 additions & 0 deletions quest/m0/archive-listing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# [M] Archive listing has one recording-scoped query

## Goal

Streaming and paginated archive listings use the same prefix and offset
convention and expose only behavior their result type can represent. Callers
cannot accidentally prepend a recording prefix twice or request directory
results that are silently discarded.

## Plan

Today `List::prefix` takes a fully prefixed Path, while `list_paginated`
takes a relative string. The latter exposes object_store's entire
PaginatedListOptions but drops common_prefixes from its result. Its bare
recording prefix can also match a sibling such as `rec-other` when listing
`rec`, because paginated backend prefixes are lexical rather than segmented.

Use an archive-owned `store::list::Query` and `Entry`, with one
recording-relative prefix/offset convention across both entry points. Keep
continuation tokens opaque and scope them to the query. Expose pagination
controls the archive supports, not arbitrary backend options. Directory
listing is outside this flat object API. Keep the generic Store and its
object_store escape hatch; do not add another storage abstraction.

Fold duplicate free path-prefix helpers into the Store/query API and make
implementation-only helpers, including check_id, crate-private. Keep module
docs and examples consistent and report the exact removed exports.

Regression tests cover a nonempty recording prefix, sibling recordings,
track prefixes, exclusive offsets, multiple pages, and every exposed option.
Passing the same logical query to either method must enumerate the same
objects when collected; backend order remains unspecified. A page must
neither silently drop directory results nor fail on neighbouring recordings.

Public API: breaking list query and pagination options in moq-archive 0.0.1.
Wire and persisted format: unchanged.

## Related

- [Archive proof](/quest/m2/archive/proof.md) - backend and replay conformance
34 changes: 34 additions & 0 deletions quest/m0/archive-ranges.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# [S] Archive group bounds use one inclusive range

## Goal

Archive callers pass group bounds without remembering an argument-order
exception. `Object::bounds`, range-named keys, reads, and validation use one
finite inclusive convention, with the persisted layout unchanged.

## Plan

`Object::bounds` returns `(smallest, largest)`, while `Key::groups`,
`Store::get_groups`, and `Object::{decode_groups,check_bounds}` take the
reverse order. Reuse standard Rust range notation: moq-net already accepts
`RangeBounds<u64>` in `Subscription::with_groups` and reader `set_groups`.
Archive objects require two finite bounds, so use `RangeInclusive<u64>` and
reject empty, reversed, or out-of-profile ranges at the boundary. Do not
invent another public Bounds type or expose moq-net's private normalization
helper; that helper supports unbounded subscription ranges with exclusive caps.

Keep largest-first filename serialization private to the codec. Public
enum construction must not bypass validation when a key is serialized.
An object's returned bounds should pass directly to lookup and validation.

Cover singleton and sparse ranges, reversed bounds, both identifier limits,
and direct key construction in the crate's CI tests. Preserve the exact
existing encoded paths and bytes. Update the examples and module docs inline;
this quest adds no recording or replay orchestration.

Public API: breaking range arguments and return values in moq-archive 0.0.1.
Wire and persisted format: unchanged.

## Related

- [Archive proof](/quest/m2/archive/proof.md) - storage and replay conformance beyond the API change
38 changes: 38 additions & 0 deletions quest/m0/e2ee-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# [M] Rust E2EE core on moq-e2ee-00

## Goal

`rs/moq-e2ee` implements profile `moq-e2ee-00` with the library shape in the
[questline](/quest/m2/e2ee/README.md): epoch-scoped generations, monotonic
identities, and no state that has to survive a publisher instance.

Reshape the 0.0.x API in place without compatibility aliases. Check publication
status separately before replacing a wire profile.

## Plan

- Replace `Credential::new(profile, context, generation, kid, secret)` with `Credential::new(Config { context, kid, secret })`, accepting an application-owned 32-byte secret. Remove `Credential::generate`: it hides the generated secret and cannot provision another process or device. Drop `profile`, `Pin`, `check_pin`, `prk_bytes`, `name_info`, `key_info`, and `key_bytes` from the public surface; the crate is the profile and the vectors run in-crate.
- Add `Credential::path(semantic) -> Path`, the epoch-free opaque broadcast name from [Opaque broadcast path](/quest/m0/e2ee-path.md), and `Generation` from `credential.generation(epoch)`. It owns `name(semantic) -> Name`, `produce(moq_net::track::Producer) -> track::Producer`, `consume(moq_net::track::Subscriber) -> track::Consumer`, and `Epoch::mint()` returning a lowercase UUIDv7 via the `uuid` crate (`v7` feature, added to `[workspace.dependencies]`). `Name` replaces `PhysicalName`; `Epoch` is a validated path segment (nonempty, no `/`, at most 65535 bytes).
- Delete `Publication` and its process-global generation set, `retransmit_datagram`, `datagram_ciphertext`, `group::Producer::ciphertext`, the producer-side datagram retention map, `GroupWindow`, `set_subscribe`, `datagram_payload_limit`, `varint_len`, and the `catalog` module. Keep `TrackKey`, `protect`, `open`, and `nonce` crate-private.
- Clones of a generation share per-track publication claims. Reopening the same physical track must not reset its nonce counters; mint a fresh epoch for a new publisher instance. Keep this state inside the generation, never in a process-global registry.
- `track::Producer` allocates sequences monotonically and refuses `create_group` or `insert_datagram` below the next sequence with `Reuse` within the claimed track. Frames are numbered by write order. The datagram plaintext cap is the constant `MAX_DATAGRAM_PLAINTEXT` (1160).
- `track::Consumer` keeps the datagram sliding window as a 1024-bit bitmask below the greatest opened sequence and marks only after a successful open. Preserve the receive limits and terminal-state behavior covered by [Receive failure](/quest/m2/e2ee/receiver-failure.md); that implementation-only fix is independently landable.
- Swap `include_str!("../../../drafts/moq-e2ee-01.json")` for the `-00` vectors, then delete `drafts/moq-e2ee-01.json` and `drafts/moq-e2ee-01.ts`; `just drafts check` globs the remaining generator. Keep the lifecycle tests the draft requires: monotonic allocation, exhaustion with failed opens counted, bounded datagram suppression, and a new epoch authenticating while the old keys do not.
- Update `doc/lib/rs/index.md`, the crate README, and the changelog to the new surface. Keep raw key material, HKDF helpers, catalog policy, and duplicate aliases out of the public exports; expose only the limits applications use to size payloads.

Public API: breaking reshape of moq-e2ee 0.0.1. Wire/interoperability: the
implemented `moq-e2ee-01` numeric generation and HKDF labels become the
draft's `moq-e2ee-00` epoch-based derivation, changing names, keys, and
ciphertext compatibility. Do not describe this as no wire change merely
because the target draft already exists. Verify publication status before
implementation and preserve any actually published profile as required by
the repository's wire-compatibility rule.

## Required

- [Opaque broadcast path](/quest/m0/e2ee-path.md) - settles the path derivation and vectors this crate implements

## Related

- [Receive failure](/quest/m2/e2ee/receiver-failure.md) - key usage accounting and waking terminal reads, without an API change
- [TypeScript E2EE core](/quest/m2/e2ee/typescript.md) - mirrors this surface name for name
File renamed without changes.
17 changes: 12 additions & 5 deletions quest/m2/reuseport-group.md → quest/m0/sock-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ socket drop are unrepresentable rather than documented.

Today the rule is left to the caller (rs/moq-sock/src/shard.rs:141-153): the
kernel numbers a reuseport group by what is in it, so closing one socket
renumbers every member after it and the filter steers their traffic to the
wrong sockets. `Member::bind` (:252-273) enforces bind order and hands the
socket straight back, and the filter goes on only when the last member binds
moves the last socket into the removed slot and invalidates existing
connection-ID steering for that socket. `Member::bind` (:252-273) enforces
bind order and hands the socket straight back, and the filter goes on only when the last member binds
(:344-349), so:

- binding fewer than all declared members exposes usable sockets before the
Expand All @@ -35,6 +35,13 @@ which is why this has not bitten. It is still a hole in the public API.
The runtime-side consumer of this shape is
[#2964](/quest/m2/2964-quic-workers-dropping-one-split-server-resizes-the.md).

## Required
Keep `moq_tokio::bind` and its current names. The re-export is useful to
existing relay callers and does not require exposing the group's formation
state. Migrate affected in-tree consumers in the API change so they compile;
[#2964](/quest/m2/2964-quic-workers-dropping-one-split-server-resizes-the.md)
owns any remaining replacement of tokio's redundant internal bookkeeping.

- [Merge dev](/quest/m1/merge-dev.md) - builds on dev-only code that reaches `main` with the merge
Public API: breaking completed-member ownership in moq-sock 0.0.1. Preserve
the published moq-tokio worker signatures. Wire: no format change. Correct
the socket-removal explanation in source comments and docs inline, and run
the formation and drop regressions on Linux CI.
Loading
Loading