Repository navigation
quest: plan epoch correctness fixes and IETF extension #5190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # [M] JS consumes use the identity of the serving announcement | ||
|
|
||
| ## Goal | ||
|
|
||
| `@moq/net` requests name the epoch of the announcement serving their path, | ||
| including covering prefixes. A newly winning announcement never gives a new | ||
| consumer a cached broadcast from the previous source. Existing consumers | ||
| remain on their instance until they drop it or its source ends. | ||
|
|
||
| ## Plan | ||
|
|
||
| Reproduced in the 2026-10-10 epoch audit in `js/net/src/lite/subscriber.ts`: | ||
|
|
||
| - Announce `pool` with epoch A, then consume `pool/job`: TRACK has no epoch | ||
| because the subscriber looks up only the exact path. Rust already uses | ||
| the resolved route's epoch. | ||
| - Consume `pool/job` through `pool`, then announce the more-specific | ||
| `pool/job` with epoch B: another consume returns the old cached broadcast. | ||
| Restart and End evict cached consumes, but the new Start does not. | ||
|
|
||
| Bind request identity and cache reuse to the serving announcement. Reuse the | ||
| existing route-resolution rules rather than adding another interpretation of | ||
| prefix precedence. A more-specific epochless announcement must not inherit | ||
| the epoch of a broader one. Inspect the shared `BroadcastCache` and IETF | ||
| subscriber for the same stale-cache behavior; IETF has no wire epoch today, | ||
| but a different epochless source still cannot reuse the old instance. | ||
|
|
||
| Add regressions for both failures, with exact-path requests as a control, | ||
| more-specific epochless routes, fallback after withdrawal, and old consumers | ||
| remaining readable while new consumers select the replacement. Same explicit | ||
| identity may reuse a broadcast; equal absent epochs do not prove identity. | ||
| Use the existing JS test lane and run cross-language interop. If routing or | ||
| invalidation work changes fanout costs, extend the relevant benchmark over | ||
| announcements and consumers instead of accepting a whole-table scan. | ||
|
|
||
| Decided 2026-10-10: these correctness fixes gate m0. Seamless JS track | ||
| handover remains separate in m1; fixing request identity does not require | ||
| building its resume pump. Update stale comments and existing concept docs | ||
| inline, with no separate guide. | ||
|
|
||
| Public API: corrected request and cache behavior, no new exported surface | ||
| expected. Wire: existing lite-07 epoch fields carry the resolved identity; | ||
| no framing change, and older versions stay epochless. | ||
|
|
||
| ## Related | ||
|
|
||
| - [JS track handover](/quest/m1/js-group-handover.md) - preserves open tracks across routes of the same explicit identity |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # [M] IETF claim responses identify the served broadcast | ||
|
|
||
| ## Goal | ||
|
|
||
| A relay learns the identity of a broadcast served under a prefix claim over | ||
| the IETF epoch extension, as it does over lite-07. A worker restarting one | ||
| output cannot splice its new groups into a cached old instance, and the | ||
| first viewer does not need a competing exact-path announcement. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-10: claim-served epochs cover both protocols but remain a | ||
| separate m1 follow-up to announcement-based IETF epochs. The existing | ||
| claim-epochs quest owns the shared broadcast model and lite-07 wire; this | ||
| quest owns the IETF response identity and mixed-protocol verification. This | ||
| split keeps the lite-07 cut independent of the IETF extension. | ||
|
|
||
| Carry the accepted broadcast's identity in the negotiated response path and | ||
| pin later requests to it. Preserve the shared claim rules for adopting a | ||
| learned epoch, refusing another instance, and keeping existing readers | ||
| sticky. Do not copy a source epoch onto different derived content, mint | ||
| epochs in relays, or infer continuity from an epochless claim. | ||
|
|
||
| Mirror the claim-epochs regression scenarios over IETF and mixed lite-07 / | ||
| IETF chains: first viewer without a cut, restarted output with cached old | ||
| groups, stale learned identity refused, and a worker draining one output. | ||
| Include an epochless viewer on an updated relay that resubscribes after the | ||
| replacement. Use mocked time and existing CI lanes; run cross-language | ||
| interop. Update the extension draft and existing concept docs in the same | ||
| PR, with `just drafts check` and `just check`. | ||
|
|
||
| Public API: reuse the shared broadcast identity model. Wire: negotiated IETF | ||
| responses report the served identity; unnegotiated peers keep their wire. | ||
|
|
||
| ## Required | ||
|
|
||
| - [IETF epochs](/quest/m1/ietf-epochs.md) - negotiation and announcement/request identity | ||
| - [Claim epochs](/quest/m1/claim-epochs.md) - the shared model and lite-07 reference behavior |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| # [L] Negotiate broadcast epochs on IETF connections | ||
|
|
||
| ## Goal | ||
|
|
||
| Rust and JS carry broadcast epochs over a negotiated moq-transport extension | ||
| on drafts 17 through 22 without changing the broadcast path. Matching | ||
| explicit epochs permit stitching; a different epoch or a different | ||
| epochless source is a new broadcast. Epochless clients remain supported on | ||
| updated relays. | ||
|
|
||
| ## Plan | ||
|
|
||
| Decided 2026-10-10 in the epoch audit interview: | ||
|
|
||
| - This is m1, after the m0 identity correctness fixes. Do not make the | ||
| extension or seamless JS handover a release blocker. | ||
| - Preserve the path. The previous `@<epoch>` suffix changed the name older | ||
| clients subscribe to; rejected in favor of negotiated metadata. | ||
| - Use a standalone SETUP-negotiated extension on drafts 17-22, where the | ||
| existing extension infrastructure applies, rather than draft 22 only. | ||
| Drafts 14-16 and peers that do not negotiate it retain their existing wire. | ||
| Integrate with the shared extension configuration in Rust and JS instead | ||
| of inventing another configuration mechanism. | ||
| - Reuse lite-07's epoch representation and identity semantics. A relay | ||
| preserves an explicit epoch, never invents continuity for an epochless | ||
| source, and refuses malformed or mismatched identities. | ||
| - Carry identity through announcements and the requests that resolve, | ||
| subscribe to, or fetch a broadcast. Pin a request to its chosen instance; | ||
| a replacement must not substitute new content into an old request. | ||
| Separate object and negative caches by identity, including joining FETCH | ||
| and concurrent old/new subscriptions. Track aliases and response handling | ||
| must preserve that separation too. This changes identity semantics, not | ||
| merely advisory announcement metadata. | ||
| - Epoch and cluster extensions negotiate independently. The cluster draft | ||
| already describes a shared negotiated NAMESPACE parameter block; make its | ||
| framing unambiguous with either extension, both, or neither. Reconcile its | ||
| namespace-only redundant-publisher semantics with explicit epoch opt-in. | ||
| - Support epochless clients on updated relays: preserve their paths and | ||
| wire framing, translate replacements into withdrawal and reannouncement, | ||
| and resolve fresh subscriptions to the current instance. Keep the relay's | ||
| internal epoch and caches separated. A same-epoch upstream route handoff | ||
| may remain invisible downstream. Existing subscriptions stay sticky; | ||
| announcement-aware players reset and resubscribe on End+Start. A player | ||
| that ignores these signals is not promised automatic recovery. | ||
| - Arbitrary older caching relays are out of scope. Base IETF object identity | ||
| is namespace, track, group, and object ID, and withdrawal does not invalidate | ||
| it. Do not claim that removing the epoch makes reused object names safe | ||
| through those relays or through clients retaining caches across broadcasts. | ||
| Immutable wire names plus discovery/translation would be separate work. | ||
| - Claim-served response identities are a separate follow-up, shared with | ||
| lite-07's claim-epochs work. Do not block announcement-based epochs on it. | ||
|
|
||
| Add a feature-specific IETF extension draft in the implementation PR, with | ||
| negotiation, identity, cache, request, downgrade, and malformed-input rules. | ||
| Update the cluster draft and existing identity/compatibility concept docs | ||
| inline. No separate migration-guide quest. The new draft must distinguish | ||
| our legacy-client behavior from base IETF's immutable-name guarantee; an | ||
| End+Start is not a general cache invalidation mechanism. | ||
|
|
||
| Verify Rust and JS with matching, different, and absent epochs; exact and | ||
| covering announcements; old subscriptions held across replacement; stale | ||
| SUBSCRIBE/FETCH refusals; and no stale catalog or media on new requests. | ||
| Exercise both directions across drafts 17-22, mixed lite-07/IETF relay | ||
| chains, and epochless clients. Cover independent epoch/cluster negotiation, | ||
| declining the extension on either side, and unchanged legacy framing. | ||
| Tests belong in existing CI lanes. Run `just check`, `just drafts check`, | ||
| and `just test interop --all`; benchmark any changed routing/cache fanout. | ||
|
|
||
| Public API: expose negotiation through the existing extension configuration | ||
| and reuse the epoch model in Rust and JS. Wire: an opt-in IETF identity | ||
| extension; no changes to unnegotiated published versions or broadcast paths. | ||
|
|
||
| ## Required | ||
|
|
||
| - [Setup extensions](/quest/m1/auth/extensions.md) - the common configuration for offering extensions | ||
|
|
||
| ## Related | ||
|
|
||
| - [Broadcast epochs](/quest/m0/broadcast-epoch/README.md) - current lite-07 identity and legacy restart behavior | ||
| - [Claim epochs](/quest/m1/claim-epochs.md) - shared broadcast identity and lite-07 response identity | ||
| - [IETF claim epochs](/quest/m1/ietf-claim-epochs.md) - learn per-output identity from an IETF claim response | ||
| - [JS track handover](/quest/m1/js-group-handover.md) - a stable JS track pump for same-epoch route changes | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.