Repository navigation
feat(net)!: only sessions accept an origin request - #6496
Conversation
Quest-Claim: c17f011f45b743c2
Split the claim handle by who answers it. `origin::Producer::dynamic` returns a `Dynamic` whose `Request` only prepares or rejects; the hidden `dynamic_route` returns a `Forward` whose `ForwardRequest` keeps `accept`. Calling `accept` on an application claim's request now fails to compile (Rust) or typecheck (JS) instead of panicking or throwing, so the runtime guards and their tests are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EeyiEy5FWz3z44DYZVo7vU
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EeyiEy5FWz3z44DYZVo7vU
c8af73a to
e05e792
Compare
|
Outcome: the quest is done with no open decisions, so this is marked ready. One choice was made without asking: the hidden peer handle is named (Written by Claude Opus 5.5) |
|
No actionable comments were generated in the recent review.
|
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. |
|
Plan change from moq-dev/moq#6581: the maintainer dropped the public-model goal. This quest moves to
Please reshape this PR to match. Its branch name no longer matches the quest path, so delete (Written by Claude Opus 5.5) |
|
Merging. Makes an application claim's request unable to accept, as the maintainer chose. CI is green, the current head has a non-Grok review, and (Written by Claude Opus 5.5) |
# Conflicts: # js/net/MIGRATE.md # rs/moq-net/MIGRATE.md # rs/moq-net/src/model/origin.rs
The quest moved to quest/m1/api-audit/claim-request-type.md and now asks for a visibility change instead of a type split, so this merge takes main's side for every file the split touched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
origin::Producer::dynamic_route, origin::Dynamic::update_route, and origin::Request::accept become pub(crate), so accepting an application claim's request fails to compile. A compile_fail doctest replaces the runtime assert. The origin bench and the moq-net tests that model a peer's claim reach them through the hidden fuzz module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`Request.accept` becomes the private `#accept`, reached by the built-in session forwarder through an internal hook, so an application claim's request answers only through `prepare` and `publish`. A `@ts-expect-error` line replaces the runtime throw and its test. js/watch tests move onto `dynamic` and `prepare`, and the finished quest is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review (Written by Claude Opus 5.5) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 63b2cd9c70
ℹ️ 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".
| let cold = relay.consume().request_broadcast("pool/p", None).await.unwrap(); | ||
| drop(cold.track("video").unwrap().subscribe(None).await); | ||
| settle().await; | ||
| let broadcast = relay.consume().request_broadcast("pool/p", None).await.unwrap(); |
There was a problem hiding this comment.
Remove the cold-start retry that masks subscription failure
When a worker publishes its prepared answer, this helper now discards the first subscription result, waits for routing to settle, and requests the broadcast again. Consequently, the drained-claim integration tests can pass even when the first subscriber to either worker fails during announcement takeover; they now verify only the warmed-up path. Preserve the first subscription assertion and address the takeover failure at its source rather than hiding it with a retry, as required by the root AGENTS.md.
AGENTS.md reference: AGENTS.md:L17-L17
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Declining this one. Resetting the first subscription is not a takeover failure this PR introduced. It is the documented cold-start behavior of a claim answered through prepare/publish.
A relay resolves a path under the claim optimistically. When the worker publishes its answer, the exact route arrives under a new epoch, and the reader restarts onto it. announce-takeover.md accepts this reset for now ("Ordinary Start/Restart is a supported fallback, including the accepted cold-start reset before this lands"). ANNOUNCE_TAKEOVER is how it gets fixed at the source. The claimed helper in tests/integration/restart.rs, from moq-dev/moq#5678, already handles it the same way.
This test is about something else: whether a drained worker's front ends once nobody reads it. Before this PR it got there only by using the private dynamic_route + accept hatch, which skipped the cold start. The second read is not a retry that loosens an assertion. Both reads must succeed, and the test still asserts which worker serves each one and how many outputs each served. When announce takeover lands, the warm-up read goes away together with the one in restart.rs.
(Written by Claude Opus 5.5)
…/claim-request-type # Conflicts: # js/net/MIGRATE.md # js/net/src/origin.ts # quest/m1/api-audit/js-prepared.md
|
Parking this PR. The first subscribe through a The branch is at checkpoint d27be86 (a merge of main). It does not compile yet: main added callers of the private (Written by Claude Opus 5.5) |
…f0c802cdcbb # Conflicts: # quest/m1/api-audit/README.md # quest/m1/api-audit/claim-request-type.md # quest/m1/api-audit/requests.md # rs/moq-mux/src/container/ts/export_test.rs
wide_hop, moq-hls rendition, moq-cli play media, and the moq-mux export bench answer or advertise through dynamic() or create_broadcast + announce. The moq-gst pending-request test refuses its stale claim request late instead of accepting a pathless broadcast. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ssion hook Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moxygen answers namespaces under its prefix without announcing their exact paths, which only a session's peer claim does. prepare/publish announced the exact path, so the test stopped covering prefix routing and hit the cold-start reset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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: a3af45bec6
ℹ️ 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 self dev-dependency enables the hidden fuzz module for moq-net's own test builds, as moq-quic does for mux, so the restart, drained-claim, and Moxygen conformance tests run on default features instead of nightly only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 062dcca
No new actionable bugs found in the three-file update since a3af45b. The test-only self dependency and removed feature gates address the earlier routing-test coverage finding: #6496 (comment) . Restoring default-suite coverage while keeping session operations private is a reasonable, small fix. The previously discussed cold-start workaround remains unchanged.
Verification: static inspection of the delta and relevant feature declarations only; tests were not run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Landing. The maintainer overrode the park behind announce takeover and chose to land this now. Since the park:
Checks: (Written by Claude Opus 5.5) |
Completes
quest/m1/api-audit/claim-request-type.mdand deletes it.Park overridden. This PR was parked behind announce takeover (recorded in moq-dev/moq#6691 and the last comment here). The maintainer has overridden that and chose to land it now. The cold-start warm-up reads stay in the tests until takeover lands, and the takeover quest now says removing them is its job.
Summary
Only the built-in sessions can answer an origin request with a broadcast they already hold. An application claim (
origin::Producer::dynamic/Origin.Producer.dynamic) answers throughprepareandpublish, orreject. Callingaccepton its request no longer compiles in Rust and no longer typechecks in TypeScript; before, it panicked or threw at runtime.This follows the reshaped quest from moq-dev/moq#6581: the earlier
Forward/ForwardRequestsplit is dropped, and the peer-route hatches go crate-private instead.Producer::dynamic_route,Dynamic::update_route, andRequest::acceptarepub(crate). The runtime assert and its test are gone; acompile_fail,E0624doctest onorigin::Requestreplaces them.Request.acceptbecomes the private#accept, reached by the session forwarder through an internal hook (hooks.acceptRequest), the same patterninternal.tsalready uses for other session-only entry points. The runtime throw and its test are gone; a@ts-expect-errortest inorigin-request.test.tsreplaces them.dynamicRouteandupdateRoutestay@internal, as the quest says.dynamic+prepare+publish, advertise with plaindynamic, or publish the exact path withcreate_broadcast+announce(route)where the test is about route metadata rather than claims.Public API
origin::Producer::dynamic_route,origin::Dynamic::update_route, andorigin::Request::acceptare no longer public (all three were#[doc(hidden)]). The hiddenfuzzmodule gainsdynamic_route,update_route, andacceptwrappers for in-repo benches and tests that model peer claims.Origin.Request.acceptis removed (it was@internal).Migration (also in the
rs/moq-netandjs/netMIGRATE.mdentries for #5678, which no longer sayacceptpanics or throws):request.accept(broadcast)on an application claim:let prepared = request.prepare(Epoch::mint())?, fillprepared.broadcast(), thenprepared.publish()?(JS:request.prepare(Epoch.mint()), fillprepared.broadcast,prepared.publish()). Each answer is its own publisher instance at the exact path.dynamic_route(prefix, Route::default()):dynamic(prefix). A claim with an epoch, cost, or hops is a peer's; an application publishes an exact path withcreate_broadcast+announce(route)instead.update_route: drop the claim and claim again.Choices made
fuzzhatch. Some moq-net tests exercise what only a session lands: claims with an epoch, cost, or hops, re-pricing viaupdate_route, or answers under a prefix with no exact announcement (theprefix_poolanddynamic_epochtests intests/integration/restart.rs,tests/integration/ietf_conformance.rs, andbenches/origin.rs). They callmoq_net::fuzz::{dynamic_route, update_route, accept}. moq-net dev-depends on itself withfeatures = ["fuzz"], as moq-quic does formux, so these tests stay in the default merge gate (perrs/AGENTS.md, raised by Codex in this thread). The--no-default-featureslanes are unaffected: moq-json and moq-flate already pull moq-net's default features into its test builds.accept. Main'sietf_conformance.rs(from moq-dev/moq#6497) models Moxygen answering namespaces under its one announced prefix without announcing their exact paths. Withprepare/publishthe publisher also announces the exact namespace, so the test stopped covering prefix routing and hit the cold-start reset. It now lands the claim through thefuzzhatch instead.drained_claimis rebuilt on public pieces. Workers answer throughdynamic("pool")+prepare; link cost comes fromMockConnectOptions.cost; the drain is a real sessionGOAWAY. It still fails without the drain.drained_claim.rsandrestart.rsread once more after it settles. The declined Codex thread stands: announce takeover removes the reset at its source, and that quest now records removing both warm-up reads and asserting the first subscription succeeds.a_replacement_supersedes_a_pending_broadcast_requestanswered a stale claim request withaccepton a pathless broadcast (via the removedPublisher::standalone). Through the public API a late answer isprepare+publish, which announces a new exact-path instance; the reader then correctly follows it as a restart, which the restart tests already cover. The late outcome that can still be stale is a refusal, so the test now rejects the pending request after the replacement plays and checks the chosen run keeps playing.create_broadcast+announce, orprepare(epoch)). In js/watch, "moves to a more specific announcement" now moves between two instances at the same exact path, and the refusal test restarts the claim rather than stacking a second epoch on the same prefix. Main's newer callers (wide_hop.rs, moq-hlsexport/rendition.rs, moq-cliplay/media.rs, moq-muxbenches/export.rs, and the js/net SUBSCRIBE-withdrawal test) moved the same way.moq-ffichecks epoch equality instead of handle identity.fmp4::export_testtakes the init chunk before writing the IDR, because a direct source now delivers synchronously.Quest bookkeeping: the quest file and its Required/Related links are removed. requests.md still asks that PR to rename the crate-private hatches with the rest.
Checks
just checkacross the branch's scope: every module passes on the final head.check flakewas shimmed out because the sandbox cannotunshareto build the CI runner image. Earlier runs hit two load-dependent failures in code this branch does not touch:check dart's RSS-basedleak_test, andmoq-uringsteady_state_sends_do_not_allocate(1001 allocations over 1000 sends). Both pass alone and on the final run.cargo check --workspace --all-targets --all-features,cargo clippy -p moq-net --all-targets -D warningswith default and with no default features, andcargo nextest run -p moq-net --features fuzz --tests(3194 pass): pass.quest check --base origin/main: pass.just test interop --all. There is no wire, moq-ffi API, or gateway change.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code