diff --git a/quest/m1/README.md b/quest/m1/README.md index 1c48d8b85d..3adc43313a 100644 --- a/quest/m1/README.md +++ b/quest/m1/README.md @@ -24,7 +24,6 @@ does not require it. The transport line in m2 assumes the single noq stack. ## Quests -- [Announce event](/quest/m1/api-net-announce.md) - publishers announce prefixes on every wire, consumers scoped by a pattern read the covered path already trimmed, with no `as_prefix().expect()` at 89 call sites - [Bindings announce match](/quest/m1/api-origin-scopes.md) - every binding takes a pattern scope and reports the announce match with its captures - [PathPrefixes](/quest/m1/api-path-prefixes.md) - the unused moq_net::PathPrefixes type is deleted before the release - [Rendition ownership](/quest/m1/api-mux-rendition.md) - one handle publishes a media track and reports its estimate, instead of five diff --git a/quest/m1/api-net-announce.md b/quest/m1/api-net-announce.md deleted file mode 100644 index 21d2fafae1..0000000000 --- a/quest/m1/api-net-announce.md +++ /dev/null @@ -1,88 +0,0 @@ -# [M] Publishers announce prefixes; consumers read trimmed paths - -## Goal - -A broadcast or dynamic route is announced as a path prefix, on every wire -version, and a consumer scoped by any pattern reads the covered path -already trimmed to its scope. Today `AnnounceUpdate { pattern, route, -active }` carries a `Pattern` even for the prefix case, so every consumer -opens with `pattern.as_prefix().expect("prefix announcement")` (80 sites -here, nine in moq.pro) and keeps a `HashSet` beside the cursor to tell a -new broadcast from a route reprice. - -## Plan - -Decided 2026-09-18 by the maintainer; a branch may already claim this, so -check open PRs before starting. - -- Publishing is prefix-only. `origin::Producer::dynamic(prefix, route)` and - `broadcast::Producer::announce` take a path, not a pattern, so the same - claim rides moq-lite and moq-transport alike. `ANNOUNCE_PATTERN` leaves - the lite-06-wip draft; PR #3746's non-prefix presented patterns go with - it. -- Consuming is a prefix too, with an optional wildcard filter on the - consume side. `announced(prefix)` opens exactly one ANNOUNCED or - SUBSCRIBE_NAMESPACE for that prefix on moq-lite and moq-transport alike; - a caller wanting `room/*/chat` passes `room` and filters the cursor with - the pattern (`announced(prefix).matching(pattern)`, or a filter argument - with the same effect). The library never derives heads from a pattern - union or multiplexes members; two heads are two calls. The pattern lives - in two places only: the token, which the relay enforces by scoping its - origin handle, and that local filter. `captures` (what each filter - wildcard stood for) is derived from the announced prefix against the - filter, so it stays and is `None` when no filter is set or the prefix - does not pin it. -- Announcements are hints; requests are the authority. A prefix route - `room` that overlaps a grant of `room/*/chat` is forwarded as - `ANNOUNCE_START room`, and a request for `room/bob/video` is refused by - `matches` at the relay, the same contract a dynamic route has today. No - set-valued intersection, clamp, or tie-break. The lite draft says so in - one sentence, so nobody reintroduces a narrowing message to fix the - over-claim. -- The cost is accepted: a scope with an empty literal head (`**/chat`) - subscribes to every announcement and filters locally. Announcements are - per broadcast and tens of bytes; a per-connection announce budget or a - head on the pattern is the answer if a relay ever measures it, not a wire - hint. -- The event is `announce::Update { path: PathOwned, captures: - Option, route: Route, kind: Kind, source: Source }` with - `Kind::{Announced, Updated, Retracted}` replacing the boolean; `path` is - the covered prefix relative to the consumer's root, trimmed by the library - so no caller does it. `captures` is `Some` only when the announced prefix - pins every wildcard of the filter: a broadcast at `room/alice/chat` under - `room/*/chat` captures `alice`, a dynamic claim of `room` under the same - filter overlaps but pins nothing and carries `None`. `source` is - `Local` or `Peer(Hop)` from the origin's bookkeeping - ([ingest source](/quest/m2/net-ingest-source.md) fills it in; the field - is settled here so it is never added after the release). The retracted - event keeps its last `route` in JS the way Rust already does. -- Delete `Announce.Update.anonymous` in JS (`js/net/src/announced.ts`); it - is computed from `route` and `Origin.isAnonymous(route)` is exported. -- `announce::Consumer` gets a `futures::Stream` impl in Rust and - `[Symbol.asyncIterator]` in JS; moq.pro wrote an `Announced` class and - the demo, room, and watch packages each carry the same `Promise.race` - drain loop. -- [Bindings announce match](/quest/m1/api-origin-scopes.md) mirrors this - shape and takes it as a blocker; the advertise half of - [Wildcard](/quest/m2/wildcard/README.md) is re-scoped to prefix claims - resolved against pattern interest. - -Public API: breaking on moq-net, @moq/net, moq-ffi, libmoq, and the -bindings, so on dev. Wire: `ANNOUNCE_PATTERN` and the `Patterns` section -leave `drafts/draft-lcurley-moq-lite.md` (lite-06-wip), and -`NAMESPACE_PATTERN` and its setup option leave -`drafts/draft-lcurley-moq-pattern.md`, which keeps only the matching and -authorization rules the token and the library share; run `just drafts -check`. Two PRs: this one carries the prefix table and the full event -shape (`path`, `Kind`, `Stream`/`asyncIterator`, no `anonymous`); PR #3746 -rebases onto it as [Bindings announce match](/quest/m1/api-origin-scopes.md) -and keeps only its surviving half. -Consumers: moq-relay, moq-stats, moq-cli, the JS packages, `demo/web`, -and moq.pro's recorder, stats, and ingest loops. - -## Related - -- [Bindings announce match](/quest/m1/api-origin-scopes.md) - the binding half, which takes the shape settled here -- [Wildcard](/quest/m2/wildcard/README.md) - the resolution side, now against prefix claims -- [Pattern grants](/quest/m2/path-patterns/interest.md) - AUTH carries pattern grants; ANNOUNCE_REQUEST stays a prefix by this decision -- [Ingest source](/quest/m2/net-ingest-source.md) - a further field the same event should carry diff --git a/quest/m1/api-origin-scopes.md b/quest/m1/api-origin-scopes.md index 0db85ba7e3..f10750aa4d 100644 --- a/quest/m1/api-origin-scopes.md +++ b/quest/m1/api-origin-scopes.md @@ -7,6 +7,10 @@ the match like Rust and JavaScript. `moq-ffi`'s `MoqOriginConsumer::announced(prefix)` scopes by a literal root today, so its only wildcard is the implicit trailing `**`. +Rust and JavaScript pattern scopes and captures landed in +[#3746](https://github.com/moq-dev/moq/pull/3746). This quest tracks only the +cross-language binding mirror that PR explicitly left unfinished. + ## Plan - Bindings, per the Cross-Package Sync checklist: `announced(prefix)` diff --git a/quest/m1/api-review-gate.md b/quest/m1/api-review-gate.md index 00a995decd..efd1ced990 100644 --- a/quest/m1/api-review-gate.md +++ b/quest/m1/api-review-gate.md @@ -16,7 +16,7 @@ file is deleted on completion) or deletes the quest with a note in `quest/m1/README.md` naming the deferred break. When the list is empty this quest is deleted too. No code. -The list: [Announce event](/quest/m1/api-net-announce.md), +The list: [Bindings announce match](/quest/m1/api-origin-scopes.md), [Rendition ownership](/quest/m1/api-mux-rendition.md). ## Related diff --git a/quest/m2/js-net-additive.md b/quest/m2/js-net-additive.md index ba226ccbd9..11f91a11bc 100644 --- a/quest/m2/js-net-additive.md +++ b/quest/m2/js-net-additive.md @@ -11,7 +11,7 @@ moq.pro's dashboard wrote (`app/src/lib/live.svelte.ts`). - `Origin.Table.broadcasts(scope): Getter>` for the "what is live" case every UI wants, beside the async iterator - from [announce event](/quest/m1/api-net-announce.md). + landed in [#3770](https://github.com/moq-dev/moq/pull/3770). - `Origin.Table.dynamic()`; `Connection.origin` is typed `Table`, which has `createBroadcast` and `request` but not `dynamic` though the object is a `Producer`. diff --git a/quest/m2/net-ingest-source.md b/quest/m2/net-ingest-source.md index 6fc0005ca4..464dff3eee 100644 --- a/quest/m2/net-ingest-source.md +++ b/quest/m2/net-ingest-source.md @@ -22,10 +22,9 @@ downstream. So: - The origin records which announce producer inserted each route (a session, an in-process producer, or a peer session). The event field - `source: Source::{Local, Peer(Hop)}` is part of the shape - [announce event](/quest/m1/api-net-announce.md) settles before the - release, since a required field added later breaks exhaustive matches - and event constructors; this quest fills it in. + `source: Source::{Local, Peer(Hop)}` extends the announce event shape + landed in [#3770](https://github.com/moq-dev/moq/pull/3770). This quest + fills it in. - `origin::Consumer::local()` is a view of the routes that entered here, so the ingest filter is one call. - A sidecar reading over the wire sees `[.., x, relay]` and cannot tell a @@ -33,14 +32,12 @@ downstream. So: its stats track so a wire consumer can, and moq.pro's Python sidecar reads that instead of a bit prefix. -Public API: additive on moq-net and @moq/net (the consumer view; the -event field is settled on dev). Wire: the relay's stats track gains a +Public API: additive on moq-net and @moq/net. Wire: the relay's stats track gains a cluster peer-set frame; name its shape in `doc/bin/relay/config.md` (stats section) in the same PR so the Python sidecar and the producer agree. ## Required -- [Announce event](/quest/m1/api-net-announce.md) - the event shape this extends - [Merge dev](/quest/m1/merge-dev.md) - starts on main ## Related diff --git a/quest/m2/origin-cpu/origin-tree.md b/quest/m2/origin-cpu/origin-tree.md index 7ee5f8152f..4826f449d3 100644 --- a/quest/m2/origin-cpu/origin-tree.md +++ b/quest/m2/origin-cpu/origin-tree.md @@ -33,4 +33,4 @@ their literal-head notification and filtering requirements. - [Route-selection CPU](/quest/m2/origin-cpu/origin-index.md) - per-broadcast alternatives - [Relay memory](/quest/m2/relay-memory.md) - memory measurements -- [Origin scopes](/quest/m1/api-origin-scopes.md) - pattern-scoped views +- [Origin scopes](https://github.com/moq-dev/moq/pull/3746) - pattern-scoped views diff --git a/quest/m2/path-patterns/interest.md b/quest/m2/path-patterns/interest.md index 177d08e07f..6b2e4a2e4b 100644 --- a/quest/m2/path-patterns/interest.md +++ b/quest/m2/path-patterns/interest.md @@ -3,10 +3,10 @@ ## Goal AUTH grants on moq-lite-06 carry the shared pattern semantics, without -changing older protocol versions. Interest stays a prefix: the 2026-09-18 -decision keeps patterns off the announce wire, so ANNOUNCE_REQUEST and +changing older protocol versions. Interest stays a prefix: [#3770](https://github.com/moq-dev/moq/pull/3770) +keeps patterns off the announce wire, so ANNOUNCE_REQUEST and SUBSCRIBE_NAMESPACE carry the prefix the caller asked for and a wildcard is -an optional filter on the consume side (see [announce event](/quest/m1/api-net-announce.md)). +an optional filter on the consume side. ## Plan @@ -23,4 +23,3 @@ matches, containment refusal, and old-version behavior. ## Required - [Lite auth](/quest/m2/auth/lite.md) - establish the AUTH exchange before upgrading its grants to patterns -- [Origin scopes](/quest/m1/api-origin-scopes.md) - the scopes this wire carries are enforced there first diff --git a/quest/m2/processor/advertise-auth.md b/quest/m2/processor/advertise-auth.md index 5748c7e277..14f44e3018 100644 --- a/quest/m2/processor/advertise-auth.md +++ b/quest/m2/processor/advertise-auth.md @@ -29,5 +29,3 @@ publish grant. ## Required - [Merge dev](/quest/m1/merge-dev.md) - the required M1 APIs must be available on main before this implementation starts -- [Origin scopes](/quest/m1/api-origin-scopes.md) - supplies the - pattern-scoped origin handles the advertise scope extends diff --git a/quest/m2/wildcard/README.md b/quest/m2/wildcard/README.md index 28f4de7316..316d9b1dd0 100644 --- a/quest/m2/wildcard/README.md +++ b/quest/m2/wildcard/README.md @@ -29,9 +29,9 @@ across the fleet in resident memory. ## Plan -Decided 2026-09-18: publishing is prefix-only on every wire and patterns -never leave the token or the client library -([announce event](/quest/m1/api-net-announce.md)). `dynamic(prefix, route)` +Decided in [#3770](https://github.com/moq-dev/moq/pull/3770): publishing is +prefix-only on every wire and patterns never leave the token or the client library. +`dynamic(prefix, route)` advertises a prefix; a suffix or catch-all claim is expressed as the widest prefix that covers it (`**` is the root) and the request is the authority, so the advertise half of this questline is re-scoped to prefix diff --git a/quest/m2/wildcard/resolve.md b/quest/m2/wildcard/resolve.md index ea3bd84591..e3cb84f9f4 100644 --- a/quest/m2/wildcard/resolve.md +++ b/quest/m2/wildcard/resolve.md @@ -108,5 +108,4 @@ Tests, at the process level with real sessions rather than an in-process stand-i ## Required -- [Announce event](/quest/m1/api-net-announce.md) - advertisements are prefixes and the request is the authority before resolution builds on them - [Merge dev](/quest/m1/merge-dev.md) - the required M1 APIs must be available on main before this implementation starts diff --git a/quest/m3/cat/verify.md b/quest/m3/cat/verify.md index a28847cefe..31f13e4619 100644 --- a/quest/m3/cat/verify.md +++ b/quest/m3/cat/verify.md @@ -51,9 +51,9 @@ rather than a set of prefixed names; `@moq/auth` stays flat. namespace without `exact_depth` appends `/**`, and an absent namespace is bare `**` with nothing appended. A field value containing `/` or `*` cannot be a segment and refuses the token naming the scope. `f*` and `*f` - are patterns the relay only admits once [Origin - scopes](/quest/m1/api-origin-scopes.md) lifts its prefix-shaped - adapter, which is why that quest is required here. A scope with a track match is refused naming the scope. + are patterns the relay admits through the pattern scopes landed in + [#3746](https://github.com/moq-dev/moq/pull/3746). A scope with a track + match is refused naming the scope. `exp` is `expires`, `moqt-reval` is `revalidate`, and `Grant::validate` keeps refusing a cadence without an expiry, so the serve default `--expires` applies to a token without `exp` @@ -85,7 +85,5 @@ gain flags. Wire: none. ## Required -- [Origin scopes](/quest/m1/api-origin-scopes.md) - the relay admits - `f*` and `*f` grants only after it - [Setup token](/quest/m3/cat/setup-token.md) - the token reaches the server's request