diff --git a/js/watch/src/broadcast.test.ts b/js/watch/src/broadcast.test.ts index e22a700df1..cd7d19d9c7 100644 --- a/js/watch/src/broadcast.test.ts +++ b/js/watch/src/broadcast.test.ts @@ -346,11 +346,12 @@ describe("cross-broadcast renditions", () => { // A derived rendition produced only on demand by a service that claims a covering prefix (a // wildcard) instead of announcing each path. Nothing announces the rendition until something // subscribes to it, so the player must list it from the claim alone. The rendition is a sibling: -// one beneath its source is already covered by the source's own announcement. +// one beneath its source is already covered by the source's own announcement. The service prefix +// is hidden, as a deployment keeps it out of listings, so the claim is only seen by opting in. describe("wildcard renditions", () => { const name = Path.from("live/foo.hang"); - const derived = Path.from("transcode/foo.hang"); - const rel = Path.normalizeRelative("../transcode/foo.hang"); + const derived = Path.from(".pro/transcode/foo.hang"); + const rel = Path.normalizeRelative("../.pro/transcode/foo.hang"); const watch = (owner: Origin.Producer) => new Broadcast({ @@ -378,7 +379,7 @@ describe("wildcard renditions", () => { await settle(); expect(videoRenditions(source)).toEqual(["source"]); - const worker = owner.dynamic(Path.from("transcode")); + const worker = owner.dynamic(Path.from(".pro/transcode")); const requests = worker.requested(); await settle(); expect(videoRenditions(source)).toEqual(["source", "transcode"]); @@ -426,7 +427,7 @@ describe("wildcard renditions", () => { try { // A catch-all (an archive) and a narrower pool both cover the derived path. const archive = owner.dynamic(Path.empty()); - const worker = owner.dynamic(Path.from("transcode")); + const worker = owner.dynamic(Path.from(".pro/transcode")); await settle(); expect(videoRenditions(source)).toEqual(["source", "transcode"]); diff --git a/js/watch/src/broadcast.ts b/js/watch/src/broadcast.ts index 8fd4dfd64f..99e8c9b801 100644 --- a/js/watch/src/broadcast.ts +++ b/js/watch/src/broadcast.ts @@ -194,7 +194,9 @@ export class Broadcast { const origin = effect.get(this.in.origin); if (!origin) return; - const announced = origin.announced(); + // Hidden routes count: a service claim under a `.`-named prefix is kept out of listings, but + // it still covers the renditions it would produce, and this set is never shown to anyone. + const announced = origin.announced(Path.Pattern.all(), { hidden: true }); effect.cleanup(() => announced.close()); this.#announced.set(new Set()); diff --git a/quest/m0/wildcard/README.md b/quest/m0/wildcard/README.md index 3314db4929..3a55d3e74a 100644 --- a/quest/m0/wildcard/README.md +++ b/quest/m0/wildcard/README.md @@ -167,10 +167,18 @@ on a generation field. 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 -(`.transcode//foo.hang`) rather than publishing beneath the source. The -source's catalog reaches the contribution through a -cross-broadcast reference. The platform layout, grants, and metering are -the deployment's; moq.pro's is in its +(`.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 +opts into them and sees a claim only when lite-07 is negotiated; the token's +scope must still reach them. 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, @@ -179,6 +187,11 @@ 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. +## Required + +- moq-lite-07 is finalized and negotiated by default, no longer + `moq-lite-07-wip`, so the player's covering check sees hidden claims + ## Related - [path-patterns](/quest/m1/path-patterns.md) - owns the pattern dialect diff --git a/quest/m1/broadcast-epoch/README.md b/quest/m1/broadcast-epoch/README.md index 0ca656287e..75cd10e878 100644 --- a/quest/m1/broadcast-epoch/README.md +++ b/quest/m1/broadcast-epoch/README.md @@ -41,7 +41,7 @@ Decided: 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 mirrors the epoch it came from - (`.transcode/pid/foo.hang/@e`, per the + (`.pro/transcode/pid/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.