Repository navigation
feat(net): announce consumers report when they have synced - #5724
Conversation
|
Paper trail: (Written by Claude Opus 5.5) |
|
#5689 merged: (Written by Claude Opus 5.5) |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sessions hold a snapshot on the origin from the moment they request announcements until the peer's initial set is in: ANNOUNCE_OK's count on lite-05+, ANNOUNCE_INIT on lite-01/02, MoQ Active Count on moq-transport, and the request or answer as a best effort elsewhere. An announce consumer is caught up once no snapshot overlapping its scope is in flight and it has read every event queued before the last one landed. A counted set cut short is a protocol violation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
announce.Consumer.caughtUp flips once the source's initial announcements are read: counted on lite-05+ (ANNOUNCE_OK active) and on moq-transport with MoQ Active Count, which JS now declares, counts as a publisher, and validates. A counted set cut short is a protocol violation. Older versions catch up on the answer or the request, as a best effort. An origin stream waits on every session still delivering an overlapping initial set, and a Reload holds it back while no session is established, so a reconnect takes caught up back until the new set lands. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lock Move the caught-up integration test into tests/integration (#5689), hold the snapshot's origin handle in a SendCell like the rest of the origin, and use @moq/clock's Milli in the Reload test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Counting a snapshot in flight took the cursor state's write guard, which wakes every waiter on it. A relay therefore woke each overlapping announce feed twice per session that connected, and that perturbation made the lite cluster triangle in cluster_unknown flap (about half of runs, never on main). Count through a read guard instead and wake only on the last landing, the one change a caught-up waiter can see. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4e7e4df to
b21aa2a
Compare
|
Paper trail for head (Written by Claude Opus 5.5) |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 19 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b21aa2abd3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A forwarded request already caught up as it opens (draft-14/15 at the root with no Solicit) never released its origin snapshot, since the listener only sees later changes. Connection.announced() and a Reload without a consume origin pumped events but never caught up. They now mirror their upstream, behind while enabled with nothing delivering, as the consume origin's hold is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The session closed cleanly and the advertiser swallowed the violation, so the peer never saw PROTOCOL_VIOLATION. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba587064db
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Zeroing the wait count under a read guard and owing the queue under a later write guard left a gap where another thread could read caught up before the owed set was in. The last landing now does both under the write guard; earlier landings still only decrement, waking nobody. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A miscounted or cut-short Active Count set, like a malformed advertisement, closed the session cleanly, so the peer never saw PROTOCOL_VIOLATION. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b78ed255e7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A cursor waited on any snapshot its patterns overlapped, even one beneath a subtree a mount shadows, so an unrelated session could hold the handle back. It now judges a snapshot as it judges a route there: not in a hole, and nameable through its mount. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be5ee59064
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A default reader waited on a session's initial set under a hidden segment, though it lists none of those routes. Rust and JS now rule such a snapshot out the way they hide its routes; a top-up feed's rule depends on the rest of the path, so it never rules a prefix out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading the count throws before the violation close ran, so the advertisement was dropped and the session stayed up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5cd60c262f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Switching a handle's upstream while caught up left the downstream caught up: the retractions landed after the new upstream was mirrored, and Producer's caughtUp() is a no-op until behind(). Pool and Reload now share one pump that retracts synchronously at teardown, goes behind first so even a parked reader takes the ends as owed, and mirrors caught up only from an open upstream. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9ec7e8c93
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # js/net/src/ietf/publisher.test.ts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Head (Written by Claude Opus 5.5) |
# Conflicts: # js/net/src/lite/subscriber.test.ts
# Conflicts: # js/net/src/wire.ts
Implements quest/m1/announce-live: an announce consumer knows when it has synced, so "not announced" can be told from "not heard yet".
Changes
Rust (
rs/moq-net)ProtocolViolation.ProtocolViolation.syncedsweeps (snapshots in flight) x (consumers):landandregisterare flat across 10..1000 on both axes.JS (
js/net)announce.Consumer.synced(aGetter<boolean>), flipping once the reader asks for the event after the last owed one, so whatever it did with that event lands first.forwardAnnouncedtakes a snapshot per announce request), andReloadholds the consume origin back while no session is established.Docs:
doc/concept/moq-lite.mdDiscovery says what synced means, which versions are exact, and the multi-source rule.Public API
announce::Consumer:is_synced(),poll_synced(&Waiter)(level-triggered, ready once closed),async synced(). Hiddenfuzz::{Snapshot, snapshot}for the bench.announce.Consumer.synced, also carried byConnection.announced()andReload.announced();announce.Producer.synced()/behind()are@internal.Ietf.activeCountFromSetup/activeCountIntoSetup,Ietf.SetupOption.ActiveCount, andParameters.activeCountfollow thehiddenpattern.Wire
No new format or draft change. JS now declares and honors the existing MoQ Active Count extension (Rust already did). Both subscribers now refuse a counted initial set that is cut short, which the drafts already require.
Iteration
main: the synced integration test moved intors/moq-net/tests/integration/(test: link each crate's integration tests into one binary #5689), the snapshot's origin handle is aSendCell, and the JS Reload test uses@moq/clock'sMilli.cluster_unknown::unknown_publisher_does_not_flap_across_a_lite_cluster_trianglefailed in about half of runs on this branch (0/10 onmain). Counting a snapshot in flight took the cursor state's write guard, which wakes every waiter, so a relay woke each overlapping announce feed twice per connecting session. That perturbed the mesh enough for a shorter path to land after a longer one and flap as a held restart. Counting now goes through a read guard and only the last landing wakes (holding_back_wakes_nobodycovers it); the triangle passes 12/12.b21aa2abd, all three findings fixed with regression tests that fail without them:opennow checkssynced.peek()after subscribing.Connection.announced()(pool) andReload.announced()without a consume origin never synced. Both now mirror their upstream, behind while enabled with nothing delivering (decision 5's rule).ba587064d, both findings fixed:b78ed255e: a snapshot beneath a mount's hole held the handle back. A cursor now judges a snapshot as it judges a route there (not in a hole, nameable through its mount).be5ee5906: a snapshot under a hidden segment held default readers (Rust and JS), and an ACTIVE_COUNT too large to read slipped past the advertisement's violation close. Both fixed with tests.5cd60c262: a handle switching upstreams while synced stayed synced over the old upstream's retractions. Pool and Reload now share one pump (pumpAnnounced) that retracts synchronously at teardown and owes those ends.c9ec7e8c9: a teardown with a snapshot in flight reported synced before the queue drained. The teardown now owes the queue like the last landing.main(Migrate network timing onto moq-clock #5681'smoq_clock, feat(net)!: let live announcements renew their auth #5695's auth rename) and renamed caught up to synced everywhere, per the maintainer:is_synced/poll_synced/synced(), JSsynced, the bench, the integration test, and the docs and draft prose.Checks
7b88bcd8f:just check(scoped to the branch) andjust test interop --all.4770abc23ande168fb270only mergemainagain (test-file andwire.tsconflicts, both sides kept).e168fb270also adds the// pending: /quest/m1/public-model/answer.mdmarkers refactor(net): narrow the model and mark what sessions reach #5794 now requires on the session-reached snapshot items (RustSnapshot,snapshot,landed; JSannounce.Producer.synced/behind,wire.OriginProducer.snapshot).just checkpasses on it.Decisions
Iterated unattended, so each took the recommended option. The maintainer can override any of them before merge.
synced(the maintainer's pick) /caught_up/caughtUp/liveas the quest said ("live" already means a track's live edge).poll_synced: ✅ level-triggered (ready whenever synced, and once closed) / edge-triggered.Reloadhold: ✅ while enabled with no session, including before a URL is set and after giving up, mirroringexpect()/ only while a connection attempt is in flight.Follow-ups
js/watch: show offline once the announcement stream has synced without the broadcast.Follow/ moq-ffi and bindings: expose synced.origin.announcedre-diffs the whole table per wake.maintoo, only rarer: in a redundant mesh, a shorter path to an UNKNOWN-hop publisher landing after a longer one is a held restart, which lite-06 and older render as an end and a start, so viewers see a flap. Worth a dedicated reproduction.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code