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
16 changes: 2 additions & 14 deletions quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@
The work in flight now. Relay hardening: legal moq-transport input never fails
a session in current interop coverage, every resource a peer can make the
relay hold is bounded by what it sent or by a budget, and no peer input panics
the process. Identity: nothing treats who published a route as what it
carries; a path and the epoch on its route are the only content identity, and
every first-party publisher that can restart mints a fresh epoch, so #4741
stalls nobody. Alongside them: fixes for the `release` line, CI cost, and the
the process. Alongside it: fixes for the `release` line, CI cost, and the
recurring audits.

## Plan

The release API gates (#3829..#3878) and the release that followed them are
done. moq.pro pins this repository's `release` line, so the release gate below
also keeps #4741 from reaching it early.
done.

Per-session request caps landed in #4820, idle fronts in #5054, and the
lost demand-poll wake in #5091. The rest of the 2026-09-29 DoS review remains
Expand All @@ -26,21 +22,13 @@ serve instead of enumerating broadcasts. Serving the relay's ingested-only
view (`origin::Consumer::local()`) to localhost workers belongs to moq.pro's
edge, which embeds moq-relay; it moved there on 2026-09-28.

Identity: the [broadcast epoch](/quest/m0/broadcast-epoch/README.md) line
gates the next release (decided 2026-10-03:
#4741 resumes an un-epoched republish into the old broadcast and stalls its
viewers). #4741 is on main, but no release ships until first-party
publishers mint epochs. Backport patches cut from `release` don't carry
#4741 and aren't gated (decided 2026-10-08).

Hygiene (decided 2026-10-19): the audits sit at the end of this list.
Each recurs once per major release: its PR adds the next run to the following
milestone, gated from m2 onward on the [release cut](/quest/m2/release/cut.md).
Each lands its fixes in its own PR and plans only what needs a decision.

## Required

- [Broadcast epochs](/quest/m0/broadcast-epoch/README.md) - every first-party publisher that can restart mints a fresh route epoch, the newest wins a path, and only routes with the same epoch resume a subscription
- [64-bit Hop IDs](/quest/m0/hop-id-64.md) - a moq-transport peer with any non-zero 64-bit Hop ID keeps its session, and Hop IDs are `u64` in Rust and JS
- [MALFORMED_AUTH_TOKEN session code](/quest/m0/malformed-auth-token-code.md) - a 0x16 close reports a malformed token instead of `unknown code=22`, and moq-net sends it for an unparseable token
- [Release shutdown backport](/quest/m0/ffi-shutdown-backport.md) - `release` publishes a non-breaking moq-ffi with an async `drain()` and qmux sessions on the QUIC stream limit
Expand Down
132 changes: 0 additions & 132 deletions quest/m0/broadcast-epoch/README.md

This file was deleted.

1 change: 0 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ audit's receive-memory, priority, and lease bugs rank ahead of that reshape.

## Required

- [Epoch correctness](/quest/m0/broadcast-epoch/README.md) - publisher identity, duplicate suppression, and catalog pinning gate the breaking cut
- [moq-congestion](/quest/m1/congestion/README.md) - one QUIC congestion-control crate with a transport-independent trait, run by `moq-quic` and published for noq
- [Release audit findings](/quest/m1/release-audit/README.md) - resolve newly identified resource, parser, playback, and interoperability risks before the cut
- [SUBSCRIBE_TRACKS follows credit](/quest/m1/listing-credit.md) - a listing holds state in proportion to what the peer reads, not to the catalog
Expand Down
2 changes: 1 addition & 1 deletion quest/m2/e2ee/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The contract is [draft-lcurley-moq-e2ee](/drafts/draft-lcurley-moq-e2ee.md), pro

- Every publisher instance mints an epoch, a UUIDv7 in lowercase text, and publishes at `<opaque>` with the epoch on its route, where `<opaque>` derives from the credential and the semantic broadcast name without the epoch. The epoch is an input to every HKDF derivation, so a restart, takeover, or explicit group sequence cannot repeat a nonce under a key: nothing is persisted across instances and no generation counter is redistributed. The epoch is the shared [`Epoch`](/doc/concept/moq-lite.md#publisher-epochs) primitive. Subscribers resolve `<opaque>` and take the epoch from its route, where the newest wins; on a wire without route epochs the application supplies it.
- An encrypting publisher refuses a shared or explicit epoch (maintainer, 2026-10-08). Two producers handed one epoch would derive the same keys and repeat every nonce. Both cores produce only under an epoch they minted themselves; consuming still binds a discovered one. Rejected: a per-instance salt. State the rule in the draft's epoch section.
- The epoch is untrusted and unauthenticated. A wrong epoch fails authentication and a withheld one denies service; neither can make a nonce repeat, because only the publisher instance chooses what it encrypts under. This is the same trust a cache needs to serve the right instance. Plaintext broadcasts adopt the same epoch by default through [broadcast epochs](/quest/m0/broadcast-epoch/README.md).
- The epoch is untrusted and unauthenticated. A wrong epoch fails authentication and a withheld one denies service; neither can make a nonce repeat, because only the publisher instance chooses what it encrypts under. This is the same trust a cache needs to serve the right instance. First-party plaintext publishers already mint the same route epoch.
- Nothing in the path says the bytes are encrypted. The format after decryption (`meeting.hang`) is inside the opaque name; a plaintext player, exporter, or matcher that opens a protected broadcast finds no catalog it can read and fails with its usual typed refusal, the same as for any format it does not support.
- One 32-byte secret authorizes the whole broadcast; HKDF-SHA-256 derives separate AES-128-GCM keys for each physical track and for grouped-frame versus datagram domains. A grouped frame uses the 96-bit nonce `uint64_be(group) || uint32_be(frame)`; a datagram uses its sequence with frame zero under the datagram domain. Empty AAD: every immutable end-to-end field is in the HKDF info or the nonce.
- Within an instance, group and datagram sequences are allocated monotonically and frames are numbered in write order, which is the whole reuse rule. There is no ciphertext retention or retransmission API: relays forward bytes unchanged, and an application that needs to resend encrypts nothing twice because it never gets the same identity twice.
Expand Down
6 changes: 6 additions & 0 deletions quest/m2/release/cut.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ tags follow this cut. This planning PR cuts and publishes nothing.
After publication, re-measure the planned wire-compat breaks against the
published versions, as CONTRIBUTING.md's release procedure describes.

This cut carries stats epochs, so it drops
[#4810](https://github.com/moq-dev/moq/pull/4810)'s release-only wall-clock
group seed: the merge of release into main keeps main's `rs/moq-stats` and
`doc/concept/stats.md`. MoQ Pro's VOD `storage.json` moves from the same
seed to its own epoch.

Recurs once per major release (decided 2026-10-19). The PR that finishes the
cut shifts the milestones up, as the root [questline](/quest/README.md)
describes. This epic's remaining publication and adoption quests move to m0,
Expand Down
3 changes: 1 addition & 2 deletions quest/m2/stats/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ its own connection. A dashboard reads both the same way a publisher does. One
shared model turns either report into a health verdict, and a bounded
preflight run reports which media layer of a broadcast is broken. Stats and
feedback cost nothing on the network unless someone subscribes. Not here: the
relay's `moq-stats` layout, which this line does not change (the
[broadcast epoch](/quest/m0/broadcast-epoch/README.md) line reshapes it);
relay's `moq-stats` layout, which this line does not change;
clock synchronization; any
requirement that a client report; and feedback as an input to billing,
authorization, or route selection.
Expand Down
3 changes: 1 addition & 2 deletions quest/m2/stats/health.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Guidance, to be settled while building:
snapshots' interval. RTT and estimated rate remain gauges read as reported.
A reset is detected by a counter decreasing or by the
reporting broadcast's path or epoch changing
([Broadcast epochs](/quest/m0/broadcast-epoch/README.md)); the sample then
([Broadcasts](/doc/concept/stats.md#broadcasts)); the sample then
starts over rather than going negative.
- Container sections such as `mpegts` are excluded from the verdict; their
counters are read by their own consumers
Expand All @@ -64,4 +64,3 @@ Public API: new health types in `hang` and `@moq/hang`. Wire: none.
## Related

- [QoS](/quest/m2/qos/README.md) - the relay's delivery counters, which a combined downstream verdict also reads
- [Broadcast epochs](/quest/m0/broadcast-epoch/README.md) - a new epoch is one way a counter reset shows
Loading