diff --git a/doc/bin/relay/cluster.md b/doc/bin/relay/cluster.md index f4c3466a5d..d313dd825a 100644 --- a/doc/bin/relay/cluster.md +++ b/doc/bin/relay/cluster.md @@ -49,18 +49,18 @@ link costs 1, which reproduces plain hop counting. Each relay adds the price of the link an announcement arrived on before forwarding it, so a route's cost is the sum of what it crossed. -Wildcard advertisements are forwarded and costed the same way as an exact-path +Prefix advertisements are forwarded and costed the same way as an exact-path route: each hop appends its identity, adds the link price, and passes the -claim on. An advertisement must be contained by one of the publisher's granted -prefixes (`grant/**`); an over-wide pattern is refused rather than clamped. +claim on. An advertised prefix must overlap the publisher's grant, or it is +refused. A prefix wider than the grant is accepted, but it only routes requests +for paths the grant covers. -Routing prefers the most specific pattern, then a fully identified hop list +Routing prefers the longest covering prefix, then a fully identified hop list over one that holds a 0 (an anonymous hop) at any depth, then the lowest cost, then the shortest hop list, breaking any remaining tie toward the newest announcement so a reconnecting publisher isn't outranked by the session it replaced. An assigned identity for an anonymous peer is local selection state -and is never written into the hop list. Resolving a non-prefix pattern into a -subscription is not implemented yet. +and is never written into the hop list. ```toml [cluster] diff --git a/js/pattern/README.md b/js/pattern/README.md index 61a687d3fc..48f9f3c12a 100644 --- a/js/pattern/README.md +++ b/js/pattern/README.md @@ -10,7 +10,7 @@ Exact path patterns for [Media over QUIC](https://moq.dev): grammar, matching, and set algebra. A pattern describes a set of broadcast paths. This package provides a shared grammar -for tokens, origin scopes, announce interests, and wildcard advertisements. Integrating +for tokens, origin scopes, and announce interests. Integrating patterns into those consumers is separate work. Literal paths stay coordinates; `@moq/net`'s path module keeps construction, joins, and prefix operations. diff --git a/quest/m0/wildcard/README.md b/quest/m0/wildcard/README.md index 6bc8b6153b..8e9173b6d0 100644 --- a/quest/m0/wildcard/README.md +++ b/quest/m0/wildcard/README.md @@ -5,16 +5,17 @@ A service claims the prefix it could serve rather than enumerating every broadcast under it; the client library filters that claim against the pattern interest the caller asked for, so nothing on the wire spells a -wildcard. A claim is priced at what starting the work would cost. Specificity wins first: a concrete -claim shadows a wildcard regardless of cost, and prices compete within the -same specificity tier. A terminal concrete refusal does not fall through to -a catch-all; its claim must be withdrawn. Retracting a wildcard stops new -work without shedding what is already running. - -Three workloads need this, and they are the three pattern shapes. A transcode +wildcard. A claim is priced at what starting the work would cost. The longest +covering prefix wins first: a concrete announcement shadows a broader claim +regardless of cost, and prices compete only among claims of the same prefix. +A terminal concrete refusal does not fall through to a catch-all; its claim +must be withdrawn. Retracting a claim stops new work without shedding what is +already running. + +Three workloads need this. A transcode worker today announces a standby derivative for every matching live broadcast, -so announcements scale as workers times broadcasts; with a suffix pattern -`**/transcode.pro` it advertises once for the whole fleet. A chat backend +so announcements scale as workers times broadcasts; claiming one service +prefix, it advertises once for the whole fleet. A chat backend cannot enumerate at all: rooms exist independently of any broadcast, and the subtree pattern `/chat/**` expresses them. An archive serving recordings over FETCH wants to say "if nobody is publishing this live, I have it", which @@ -33,11 +34,12 @@ across the fleet in resident memory. 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 -claims resolved against pattern interest. The three workloads above still -hold: the transcoder claims the root and refuses what it will not serve. +advertises a prefix; the catch-all claim is the root prefix, and the request +is the authority, so the advertise half of this questline is re-scoped to +prefix claims resolved against pattern interest. The three workloads above +still hold: the transcoder claims its service prefix +([Where derived output lives](#where-derived-output-lives)), and the archive +claims the root and refuses what it does not have. Resolve and Demand are additive and land on main. Both are done on the line branch (#4050 re-resolves on a refusal; 9d059b1b9 lists and demands covered renditions in the browser player), so main no longer lists them; the line @@ -50,16 +52,15 @@ production cost: zero for a live publish, something large for a standby that would have to start working (a cold transcoder)" (`drafts/draft-lcurley-moq-lite.md`). `moq_auth::Claims.publish` and `origin::Producer` gain versioned patterns through -[Path patterns](/quest/m1/path-patterns.md), so advertisements reuse the -same exact containment check. `Cost { warm, cold }` +[Path patterns](/quest/m1/path-patterns.md), so tokens and filters reuse the +same matcher; advertisements stay prefixes. `Cost { warm, cold }` (`rs/moq-net/src/model/origin.rs:426`) is the route cost since [#2925](https://github.com/moq-dev/moq/pull/2925). [moq#3225](https://github.com/moq-dev/moq/pull/3225) moved a long way toward -this. An announcement carries a `Pattern` covering a set of paths. Rust -`announce::Update.pattern` and TypeScript `Announce.Update.pattern` use the -matcher directly, so callers explicitly select prefix-shaped claims when -they need a concrete broadcast path. +this, and #3770 settled the wire: an announcement carries a path prefix on +every protocol, and a consumer filters announced paths against its pattern +interest locally. The routing table exists too. `Consumer::request_broadcast` resolves a local broadcast first, then `best_server`: the longest covering prefix, filtered by @@ -69,11 +70,11 @@ announced it and cached per prefix in `ServeState.served` (`:764`). That is the lookup the old `origin::Dynamic` could not provide, and it is what resolve extends rather than replaces. -Request resolution, by contrast, is still prefix-only (`best_server` in -`rs/moq-net/src/model/origin.rs`). The pattern matcher itself exists: -`moq_net::{Pattern, Patterns, Segment}` and `Path.Pattern` / +Request resolution is prefix-only (`best_server` in +`rs/moq-net/src/model/origin.rs`) and stays that way. The pattern matcher +itself exists: `moq_net::{Pattern, Patterns, Segment}` and `Path.Pattern` / `Path.Patterns` in `js/net/src/path.ts` own the shared matching, containment, -specificity, and rebasing advertisements reuse. +specificity, and rebasing tokens and filters reuse. What is genuinely missing, beyond patterns themselves, is content identity. Announcement `Epoch` was specified into lite-06 by @@ -91,40 +92,37 @@ field. dialect is what tokens and the consume-side filter use, matched by the shared matcher, so nothing resembles a second grammar and nothing on the wire spells a wildcard. -- **Most specific pattern wins, and its refusal is final.** This is the rule +- **Longest prefix wins, and its refusal is final.** This is the rule routing already follows: `best_server` filters to the longest covering prefix before it compares cost, and the lite draft says the same, matching - longest-prefix-match wherever it appears. When several patterns match one - path, only the tier selected by the matcher's shared structural specificity is - consulted; equal-specificity patterns - form one pool that cost and the request hash order. A terminal refusal from - the winning tier IS the answer and never falls through to a less specific - pattern, so a transcoder refusing a path does not leak the request to the - archive's catch-all, and one unserved path still costs one round trip. The - capacity re-resolution below stays within the tier, refuser excluded. The - accepted consequence: an offline derivative (a recording of - `foo.hang/transcode.pro`) is not reachable through the catch-all, because - the more specific transcode pattern shadows it. -- **A wildcard is a POOL, not a competitor.** Several advertisers of one - pattern is the normal state, not a hazard: every transcode worker advertises - `**/transcode.pro` and takes a share. What distributes them is a + longest-prefix-match wherever it appears. Advertisers of one prefix form one + pool that cost and the request hash order. A terminal refusal from the + winning tier IS the answer and never falls through to a shorter prefix, so a + transcoder refusing a path does not leak the request to the archive's + catch-all, and one unserved path still costs one round trip. The capacity + re-resolution below stays within the tier, refuser excluded. The accepted + consequence: an offline derivative is not reachable through the catch-all + while a longer prefix covers it. +- **A claim is a POOL, not a competitor.** Several advertisers of one + prefix is the normal state, not a hazard: every transcode worker claims the + same prefix and takes a share. What distributes them is a deterministic hash of the REQUESTED path against each advertiser, so distinct - paths spread rather than one advertiser winning the whole pattern. + paths spread rather than one advertiser winning the whole prefix. Distribution is the requirement, not any particular pair: a correct hash may legitimately rank the same advertiser first for two given paths, so what must hold is that a large path set spreads and that one path always resolves the same way. Cost orders the pool first, which keeps work local and makes a distant advertiser the overflow rather than an equal peer. -- **A wildcard is priced, not special-cased.** Within a tier, route selection - stays one comparison on one metric. Concrete-versus-wildcard is not decided - by price at all: a concrete claim is maximally specific, so "most specific - wins" above already shadows every pattern behind it at any cost. The +- **A claim is priced, not special-cased.** Within a tier, route selection + stays one comparison on one metric. Concrete-versus-claim is not decided + by price at all: a concrete announcement is the longest prefix, so "longest + prefix wins" above already shadows every claim behind it at any cost. The accepted consequence follows from that rule's finality: a live session's - concrete claim shadows a healthy wildcard pool even when its service is + concrete claim shadows a healthy pool even when its service is broken, its terminal refusal does not fall through, and the shadow lasts exactly as long as the claiming session that carries it. - The seed still has a floor, because standby and running claims of equal - specificity do meet: a standby concrete claim (`with_cost(1000)` is the + The seed still has a floor, because standby and running claims of the same + prefix do meet: a standby concrete claim (`with_cost(1000)` is the existing per-broadcast convention) shares a tier with a running publisher's concrete announcement. The floor MUST exceed the deployment's enforced maximum charged-link count @@ -133,23 +131,21 @@ field. mesh starts a second encode of a stream it is already serving. That floor replaces the ad-hoc standby bias the moq.pro (downstream) transcode worker carries today. -- **One cost varint, not the pair.** `Cost` is `{ warm, cold }` because a relay - that is carrying a broadcast discounts the warm half. A wildcard carries - nothing and can never be warm, so the two halves are provably equal and the - message carries one value. `From` already means exactly this. - **A wildcard is a capability, not an inventory.** It advertises what the sender could serve, never that a given path exists. Refusal is how a specific path is denied. This is why an over-claiming advertisement is not a defect: the catch-all `**` is legal, and answering "not that one" is the mechanism. -- **Containment against the publish scope is what authorization checks.** An - advertised pattern MUST be contained by the sender's granted patterns (the - matcher's containment check). This handles literal-headed and leading-star - patterns identically and refuses any attempted widening rather than clamping - it. Fleet-wide services use the cluster identity; a customer service may - advertise only the exact set its own v1 grant contains. -- **Wildcards are visible to subscribers.** A subscriber sees every pattern - matching under its scope, rebased by the matcher's exact set-valued operation, - and duplicates combine into one. That is the point: it tells a client it may subscribe to +- **Overlap with the publish scope is what authorization checks.** An + advertised prefix MUST overlap the sender's granted patterns or it is + refused. A prefix wider than the grant is accepted, but it only routes + requests for paths the grant covers. Fleet-wide services use the cluster + identity; a customer service serves only what its own v1 grant contains. + Until [Advertise-only authorization](/quest/m1/processor/advertise-auth.md) + lands, the publish scope stands in for advertising; a credential with its own + advertise scope is checked against that instead. +- **Claims are visible to subscribers.** A subscriber sees every advertised + prefix under its scope, filtered locally like any other announcement. That + is the point: it tells a client it may subscribe to matching paths, and its withdrawal tells the client the capability is gone. This is what makes a lazily-produced rendition discoverable without the composer waiting for an announcement that only demand would produce. The @@ -199,71 +195,37 @@ field. ### Where derived output lives -Suffix matching lets a contribution be published where it is addressed, a -descendant of its source. This is the moq.pro (downstream) deployment shape, -and it is what the suffix pattern form exists for: - -```text -pid/foo.hang source -pid/foo.hang/catalog.pro combined catalog, edge-composed -pid/foo.hang/transcode.pro the transcode contribution -pid/foo.hang/transcribe.pro the transcription contribution -``` - -The `.pro` segment suffix is both the routed pattern and the platform-output -marker: `**/transcode.pro` routes every project's transcode demand to the -worker pool, and a segment ending in `.pro` is the one predicate every source -rule matcher excludes, so platform output is never recursively transcoded or -recorded. - -The rejected alternative publishes contributions at mirrored paths in reserved -namespaces (`.transcode//...`) hidden by an origin-consumer overlay, -because prefix-only matching needs the variable part of a path trailing. That -overlay is not a view transform: `pid/foo` and `.transcode/pid/foo` are -separate tree leaves with separate broadcast fronts, so it has to build a -logical front across roots that re-owns route selection, content identity, the -split-horizon guard, and splicing. The suffix pattern needs none of it while -keeping what the mirror buys: - -- **The grant needs no transform.** The customer addresses - `foo.hang/transcode.pro`, a descendant of `foo.hang`, so an existing grant - covers it by ordinary segment-aware prefix. No companion-grant rule, no - atomic `.pro/` scope, and nothing minted differently, which matters because - customer-issued tokens are minted by integrations the platform does not - control. -- **Metering is untouched.** The published path is rooted at `pid`, so the - platform's egress metering sees the customer path with no special case at - all. -- **The wildcard is fleet-wide.** The suffix is project-agnostic, so a worker - advertises once for every project rather than once per project, which is what - removes project discovery entirely. -- **Takeover is single-front.** A worker's concrete announcement lands at the - literal path the wildcard served, so wildcard-versus-concrete and - worker-versus-worker collisions are ordinary route selection at one tree node, - not a cross-root front. - -What the mirror buys and this deliberately gives up: a customer holding -`publish: ["pid/"]` CAN publish `foo.hang/transcode.pro` themselves, competing -with or forging platform output. Both then resolve at one path, cost decides, -and a live customer broadcast beats the worker's standby seed. That is confined -to their own namespace, self-sabotage of their own catalog, never another -project's, and is cheaper to allow and document than a reserved-name registry -or a token transform. The mirror's SUBSCRIBE-only overlay asymmetry existed to -prevent exactly this and goes with it. - -The archive is the same shape at the source path itself: a recording IS the -broadcast, served from storage through the catch-all pattern. A wildcard 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. +A prefix claim needs the variable part of a path trailing, so a fleet-wide +service claims its own prefix and mirrors the source path beneath it +(`.pro/transcode//foo.hang`, moq.pro's convention) rather than publishing +beneath the source. The source's catalog reaches the contribution through a +cross-broadcast reference. + +The leading `.` is deliberate. Existing customers on moq-lite-06 or older must +never see `.pro/` broadcasts, which could confuse their business logic. Those +versions cannot opt into hidden routes, so the relay never announces them +there. Hidden routes are a moq-lite-07 feature, so the player's covering check +(Demand, done on the line branch) opts into them and sees a claim only when +lite-07 is negotiated. A customer who wants transcodes upgrades, or +subscribes to the explicit `.pro//...` path, which works on any +version. Grants and metering are the deployment's; moq.pro's are in its +[wildcard questline](https://github.com/moq-dev/moq.pro/blob/main/quest/m2/wildcard/README.md). + +The archive serves the source path itself: a recording IS the broadcast, +served from storage through the root claim, and a live publisher's concrete +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. ## Related - [path-patterns](/quest/m1/path-patterns.md) - owns the pattern dialect - and the shared matcher advertisements reuse -- [archive](/quest/m1/archive/README.md) - an archive advertises the catch-all - pattern, and its catalog names the generations a wildcard cannot + and the shared matcher tokens and filters reuse +- [archive](/quest/m1/archive/README.md) - an archive claims the root, and its + catalog names the generations a claim cannot - [Cluster routing](/quest/m1/cluster-routing.md) - origin selection by cost - with an HRW tie-break, built on this line's specificity -- [Broadcast epochs](/quest/m1/broadcast-epoch/README.md) - derived output moves under the - source's `@` segment, which the suffix patterns still match + with an HRW tie-break, built on this line's longest-prefix rule +- [Broadcast epochs](/quest/m1/broadcast-epoch/README.md) - derived output + mirrors the source path, `@` segment included +- [Suffix announce](/quest/m3/suffix-announce.md) - moq-lite-only suffix + claims, deferred until a service prefix cannot express one diff --git a/quest/m1/auth/README.md b/quest/m1/auth/README.md index b95317d571..ab481d4558 100644 --- a/quest/m1/auth/README.md +++ b/quest/m1/auth/README.md @@ -120,7 +120,7 @@ existing lite-06 ALPN. ## Related -- [Pattern interest](/quest/m1/path-patterns.md) - moves AUTH's legacy wire prefixes to patterns along with ANNOUNCE_REQUEST +- [Pattern interest](/quest/m1/path-patterns.md) - moves AUTH's legacy grant prefixes to patterns; ANNOUNCE_REQUEST stays a prefix - [Expiring media grants](/quest/m1/processor/grant-lease.md) - a worker's lease renewal is a new in-band token - [P2P](/quest/m1/p2p/README.md) - the first consumer of hop-bound peer grants diff --git a/quest/m1/auth/lite.md b/quest/m1/auth/lite.md index 08b65bd7f6..6d54e56217 100644 --- a/quest/m1/auth/lite.md +++ b/quest/m1/auth/lite.md @@ -147,5 +147,5 @@ On main, additive. ## Related -- [Pattern interest](/quest/m1/path-patterns.md) - moves the prefix - fields here and in ANNOUNCE_REQUEST to patterns together +- [Pattern interest](/quest/m1/path-patterns.md) - moves AUTH's grant + prefixes to patterns; ANNOUNCE_REQUEST stays a prefix diff --git a/quest/m1/broadcast-epoch/README.md b/quest/m1/broadcast-epoch/README.md index 9e0ac40d40..337297edc3 100644 --- a/quest/m1/broadcast-epoch/README.md +++ b/quest/m1/broadcast-epoch/README.md @@ -40,10 +40,10 @@ Decided: bare `foo`, since a route covers its descendants, not its parent. A bare-name viewer behind one needs a publisher that opts out with the raw prefix route. Document this rather than promise it works. -- Derived output lives under the epoch it came from - (`pid/foo.hang/@e/transcode.pro`), so nested epochs must parse. This moves - the [wildcard](/quest/m0/wildcard/README.md) line's derived-output example - down one segment, and its suffix patterns still match. +- Derived output mirrors the epoch it came from + (`.pro/transcode//foo.hang/@e`, per the + [wildcard](/quest/m0/wildcard/README.md) line's derived-output layout), so + the service's prefix claim still covers it. This README owns: diff --git a/quest/m1/cluster-routing.md b/quest/m1/cluster-routing.md index c93f1f1df5..7345104e27 100644 --- a/quest/m1/cluster-routing.md +++ b/quest/m1/cluster-routing.md @@ -48,8 +48,8 @@ make MoQ's common case. origin id, and forwards along its shortest path. Distance compares cost, then hop count, so every hop strictly shortens it even across `?cost=0` links. That is a shortest path to a virtual node linked to every origin, so - it is loop-free whenever relays agree on the topology. Specificity still - ranks first, per [Wildcard](/quest/m0/wildcard/README.md). + it is loop-free whenever relays agree on the topology. The longest covering + prefix still ranks first, per [Wildcard](/quest/m0/wildcard/README.md). - The first relay's choice rides the SUBSCRIBE, and transit relays forward toward that origin by topology alone, never re-selecting. Re-selection against another existence view loops: a relay that lost a specific claim @@ -114,7 +114,7 @@ make MoQ's common case. ## Required - moq.pro workers stop electing on hop chains, reading the relay's local origin instead ([moq.pro voice-local-origin](https://github.com/moq-dev/moq.pro/blob/main/quest/m0/voice-local-origin.md)) -- [Wildcard](/quest/m0/wildcard/README.md) - the specificity, pool spread, and reply identity this selection builds on +- [Wildcard](/quest/m0/wildcard/README.md) - the longest-prefix rule, pool spread, and reply identity this selection builds on - moq.pro's routing simulator reports ([quest](https://github.com/moq-dev/moq.pro/blob/main/quest/m1/routing-simulator.md)) ## Related diff --git a/quest/m1/path-patterns.md b/quest/m1/path-patterns.md index 90b43fb304..691bcf1dc3 100644 --- a/quest/m1/path-patterns.md +++ b/quest/m1/path-patterns.md @@ -3,9 +3,9 @@ ## Goal Every predicate over a MoQ broadcast path uses one matcher. Tokens, -origin scopes, announce interests, public access rules, and wildcard -advertisements can express `pid/*/chat` and `**/transcode.pro` without -maintaining competing glob dialects. +origin scopes, announce interests, and public access rules can express +`pid/*/chat` and `**/*.hang` without maintaining competing glob dialects. +Routing is not a predicate here: advertisements stay prefixes. Literal paths remain coordinates, not sets. Roots, joins, exact broadcast names, URL paths, filesystem paths, and object-store keys keep their own @@ -98,5 +98,5 @@ matches, containment refusal, and old-version behavior. ## Related -- [Wildcard advertisements](/quest/m0/wildcard/README.md) - routing adopts the - matcher while retaining its own cost, pool, refusal, and resolution work +- [Wildcard advertisements](/quest/m0/wildcard/README.md) - routes on prefix + claims; the matcher only filters them against consume-side interest diff --git a/quest/m1/processor/README.md b/quest/m1/processor/README.md index 041fc85997..2adda56916 100644 --- a/quest/m1/processor/README.md +++ b/quest/m1/processor/README.md @@ -5,7 +5,9 @@ A customer runs a worker in its own environment, connects outbound to a MoQ deployment, reads only eligible source media, and publishes an on-demand contribution under the processor's own prefix, mirroring the source path -(for example `./`). The platform supplies +(for example `.pro//`, the +[wildcard](/quest/m0/wildcard/README.md) line's derived-output layout). The +platform supplies registration, scoped credentials, routing, demand, status, and usage visibility; it does not upload or execute customer code. diff --git a/quest/m1/processor/advertise-auth.md b/quest/m1/processor/advertise-auth.md index 1c8fc2bead..d3dc514541 100644 --- a/quest/m1/processor/advertise-auth.md +++ b/quest/m1/processor/advertise-auth.md @@ -21,15 +21,20 @@ every wire (Wildcard's decision) and suffix routing is dropped, so leading-star and suffix advertise patterns have nothing to authorize. Token claim patterns keep their suffix support for publish and subscribe. +Decided: an advertised prefix must overlap the advertise scope, not sit +inside it, and a wider claim only routes the requests the scope covers. This +matches how the relay authorizes advertisements today. + Preserve current customer credentials in the wire and authorization design: existing claims retain their current publish-implies-advertise behavior, while the new v1 claim separates the capabilities. Land the claims, SDK, origin-scope, relay authorization, and tests without combining the release or the moq.pro (downstream) pin rollout into this quest. -Cover containment, rebasing, missing versus empty advertise scope, v0 -compatibility, token revalidation, concrete announce, publish, FETCH, and a -prefix demand that receives only an exact short-lived publish grant. +Cover overlap and per-request filtering, rebasing, missing versus empty +advertise scope, v0 compatibility, token revalidation, concrete announce, +publish, FETCH, and a prefix demand that receives only an exact short-lived +publish grant. ## Required diff --git a/rs/moq-net/src/path/mod.rs b/rs/moq-net/src/path/mod.rs index 21acabb44e..ce3f0c930c 100644 --- a/rs/moq-net/src/path/mod.rs +++ b/rs/moq-net/src/path/mod.rs @@ -4,9 +4,9 @@ //! segment-aware prefix operations. [`Pattern`] describes a set of paths with //! wildcards, and [`Patterns`] is a union of them reduced by containment. The //! grammar and algebra live in [`moq-pattern`](moq_pattern); this module -//! re-exports them beside [`Path`] so grants, origin scopes, announce interests, -//! and wildcard advertisements can share one dialect. Literal path construction -//! and wire decoding retain their existing behavior. +//! re-exports them beside [`Path`] so grants, origin scopes, and announce +//! interests can share one dialect. Literal path construction and wire +//! decoding retain their existing behavior. pub use moq_pattern::{InvalidPattern, Pattern, Patterns, Segment, Specificity}; diff --git a/rs/moq-pattern/README.md b/rs/moq-pattern/README.md index bcaeddbcf4..5053dbf492 100644 --- a/rs/moq-pattern/README.md +++ b/rs/moq-pattern/README.md @@ -7,7 +7,7 @@ Exact path patterns for [Media over QUIC](https://moq.dev): grammar, matching, and set algebra. A pattern describes a set of broadcast paths. This crate provides a shared grammar -for tokens, origin scopes, announce interests, and wildcard advertisements. Integrating +for tokens, origin scopes, and announce interests. Integrating patterns into those consumers is separate work. Literal paths stay coordinates; `moq-net`'s `Path` and `@moq/net`'s path module keep construction, joins, and prefix operations.