From 39bf602608ae52dc9b0e5ad260c4fecce7b95ffc Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 28 Sep 2026 10:55:04 -0700 Subject: [PATCH] quest(wildcard): block the line on the #4279 datagram, origin, and benchmark findings Co-Authored-By: Claude Opus 5.5 --- quest/m1/wildcard/README.md | 8 ++++- quest/m1/wildcard/datagram-start.md | 48 +++++++++++++++++++++++++++++ quest/m1/wildcard/js-origin.md | 35 +++++++++++++++++++++ quest/m1/wildcard/pool-bench.md | 29 +++++++++++++++++ 4 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 quest/m1/wildcard/datagram-start.md create mode 100644 quest/m1/wildcard/js-origin.md create mode 100644 quest/m1/wildcard/pool-bench.md diff --git a/quest/m1/wildcard/README.md b/quest/m1/wildcard/README.md index 86ccf71609..c92f3bd785 100644 --- a/quest/m1/wildcard/README.md +++ b/quest/m1/wildcard/README.md @@ -1,4 +1,4 @@ -# [S] Wildcard advertisements +# Wildcard advertisements ## Goal @@ -183,6 +183,12 @@ announcement shadows it. A claim names no generation, so a client that must distinguish recording generations reads the catalog's archive entry ([archive](/quest/m1/archive/README.md)) rather than announce state. +## Quests + +- [Datagrams behind SUBSCRIBE_START](/quest/m1/wildcard/datagram-start.md) - no datagram crosses a subscription's start in either direction, in Rust or JS +- [JS origin granularity](/quest/m1/wildcard/js-origin.md) - `@moq/net` tracks a reply's origin at the same granularity as Rust +- [Pool resolution benchmark](/quest/m1/wildcard/pool-bench.md) - route resolution is benchmarked over pool size and requested paths + ## Related - [path-patterns](/quest/m1/path-patterns.md) - owns the pattern dialect diff --git a/quest/m1/wildcard/datagram-start.md b/quest/m1/wildcard/datagram-start.md new file mode 100644 index 0000000000..21e9740615 --- /dev/null +++ b/quest/m1/wildcard/datagram-start.md @@ -0,0 +1,48 @@ +# [M] Datagrams behind SUBSCRIBE_START + +## Goal + +On lite-07, no datagram crosses a subscription's SUBSCRIBE_START in either +direction, in Rust or JS: a publisher commits the start only for something it +actually sends, never sends a group below the start it announced, and a +subscriber delivers a datagram only after that subscription's own +SUBSCRIBE_START has named an admitted origin. + +## Plan + +[#4279](https://github.com/moq-dev/moq/pull/4279) made SUBSCRIBE_START +(SUBSCRIBE_OK) carry the serving origin and go out ahead of the first group +served by stream or datagram. Its last Codex round left three P1s unanswered, +and the PR auto-merged before CI. The maintainer ruled in the 09-28 +merged-PR audit that all three block the line: + +- **An oversized first datagram commits the start** + ([r4117485530](https://github.com/moq-dev/moq/pull/4279#discussion_r4117485530)). + Rust's `Recv::Datagram` arm in `rs/moq-net/src/lite/publisher.rs` calls + `start` before `serve_datagram` drops a body over `max_datagram_size`, and + JS `#runDatagrams` in `js/net/src/lite/publisher.ts` awaits + `responses.start` before its size check. A dropped datagram at sequence 10 + can so announce a start of 10 and discard a valid group at 5. Decide + whether a datagram can be sent before resolving the start from it. +- **JS start-sequence race** + ([r4117485532](https://github.com/moq-dev/moq/pull/4279#discussion_r4117485532)). + `SubscribeResponses.start` reserves `#started` for whichever loop arrives + first, but the write runs later through the `#writes` chain, so the group + loop can pop a lower sequence in between and send group 5 after a START + for 10. Choose the start and apply its floor atomically, or revalidate a + group popped while the start was pending. +- **FETCH_OK admits a datagram before its own SUBSCRIBE_START** + ([r4117485533](https://github.com/moq-dev/moq/pull/4279#discussion_r4117485533)). + `route_datagram` in `rs/moq-net/src/lite/subscriber.rs` gates only on the + shared track `Provenance` being admitted. A FETCH on the same track can + admit it through FETCH_OK while this subscription has not started, so a + racing datagram is delivered, and a later START naming another origin is + caught only after content was exposed. Require this subscription's own + start as well. Check whether the JS subscriber has the same gap. + +Each fix gets a regression test that fails without it, in the language it +touches. + +## Related + +- [Wildcard](/quest/m1/wildcard/README.md) - the line this blocks diff --git a/quest/m1/wildcard/js-origin.md b/quest/m1/wildcard/js-origin.md new file mode 100644 index 0000000000..39a63d5330 --- /dev/null +++ b/quest/m1/wildcard/js-origin.md @@ -0,0 +1,35 @@ +# [S] JS origin granularity + +## Goal + +`@moq/net` tracks the origin an upstream reply names at the same granularity +as Rust, and handles a second, different origin the way Rust does, so a JS +node that republishes never labels one origin's content as another's. + +## Plan + +[#4279](https://github.com/moq-dev/moq/pull/4279) had JS record the origin +an upstream SUBSCRIBE_OK or FETCH_OK names on the consumed broadcast's shared +state (`js/net/src/broadcast.ts`), and the latest reply wins. Rust records it +per copy of a track (`track::Provenance`) and only admits a replacement +naming the same origin. Codex asked for a conflicting name to be refused +([r4112837960](https://github.com/moq-dev/moq/pull/4279#discussion_r4112837960)). +The agent declined, since a later request for the same broadcast can +legitimately land on a front serving another origin, and left the +granularity question to the maintainer +([r4113954489](https://github.com/moq-dev/moq/pull/4279#discussion_r4113954489)). +The maintainer decided in the 09-28 merged-PR audit that JS must match Rust. + +- Move the origin to the level Rust keeps it at, so two tracks of one + broadcast served by different origins stay distinct. +- A reply naming a different origin for content already labeled follows + Rust's rule rather than overwriting silently. +- A republished broadcast advertises, per track, the origin that actually + served it, or a random one when nothing upstream named one. + +Test the mid-life origin change JS previously absorbed, and pin that JS and +Rust agree on it in the interop suite if the scenario is reachable there. + +## Related + +- [Wildcard](/quest/m1/wildcard/README.md) - the line this blocks diff --git a/quest/m1/wildcard/pool-bench.md b/quest/m1/wildcard/pool-bench.md new file mode 100644 index 0000000000..2c5ed36d25 --- /dev/null +++ b/quest/m1/wildcard/pool-bench.md @@ -0,0 +1,29 @@ +# [S] Pool resolution benchmark + +## Goal + +A benchmark sweeps pool size against requested-path count for route +resolution, so a cost that grows with the pool or the path set instead of the +touched path shows up as a slope. + +## Plan + +[#4279](https://github.com/moq-dev/moq/pull/4279) keyed `route_order`'s tie +break on a hash of the requested path, so resolving a path now scans the +equal-cost pool and hashes the path with every candidate's hops +(`rs/moq-net/src/model/origin.rs`). Only a correctness test +(`equal_cost_pool_spreads_paths`, 4 members by 64 paths) covers it. Codex +asked for the two-axis sweep AGENTS.md requires for fan-out +([r4117485535](https://github.com/moq-dev/moq/pull/4279#discussion_r4117485535)), +and the PR listed it as a known gap. The maintainer ruled in the 09-28 +merged-PR audit that it blocks the line. + +Add it beside the existing origin benchmarks in `rs/moq-net/benches/`. If the +slope shows resolution scaling with the pool in a way that matters, say so in +the PR rather than optimizing here. The PR's other known gap, tracks per +front for the driver's per-event admission walk, is worth sweeping in the +same change if it is cheap. + +## Related + +- [Wildcard](/quest/m1/wildcard/README.md) - the line this blocks