Repository navigation
refactor!: the final API audit narrows surfaces added since the audit - #8088
Conversation
Quest-Claim: 8e4cd50cccc19a40
Quest-Claim: 8e4cd50cccc19a40
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Narrow the public surface of moq-quic, moq-congestion, moq-sock, moq-tokio,
moq-uring and moq-relay to what has a consumer:
- moq-quic: send/recv live at the root only; stats, Streams and Datagrams
under connection only. Remove connection::Event and Connection::poll,
transport::Config.max_outgoing_bytes_per_second, and make poll_acked and
poll_handshake_confirmed test-only.
- moq-congestion: drop the root Bbr3/Cubic/Gcc/Scream re-exports, make
Bbr3 and Cubic crate-private, and remove Init.max_pacing_rate, which
nothing set once the transport knob went.
- moq-sock: demux::{classify, Class, Queue::SHARE} are private.
- moq-tokio: listen.implementation and connect.backoff.healthy are
code-only; tcp and websocket Listener::accept return Result; Forward::configured
is private.
- moq-relay: the uring module is crate-private.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- hang: Catalog::media() -> without_ext(), so `media` names only the catalog's media section.
- moq-mux: container::Consumer::set_max_buffer and DEFAULT_MAX_BUFFER go crate-private;
fmp4::{MAX_HELD_BYTES, MAX_METADATA_BYTES, MAX_FRAGMENT_SAMPLES, MAX_TRACKS} go private;
fmp4::Import::with_passthrough -> with_cmaf, matching the CLI's --cmaf.
- moq-hls: import::Config.passthrough -> cmaf; Broadcaster::is_clone and
Rendition::{interval, segment_length} go crate-private.
- moq-rtmp: Client/Play::with_max_delay -> with_delay (the FLV release delay, CLI --delay).
- moq-srt: Client::with_max_delay -> with_latency (the SRT receive latency, CLI --latency).
- moq-stats: consume::Consumer::group and consume::GroupConsumer become test-only.
- moq-cli: drop the hidden --mtls-peer/--mtls-upstream flags, which never shipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Datagram lives only at `moq_net::datagram::Datagram`; the root re-export is gone.
- `Error::{EmptySegment, InvalidEscape}` fold into `Error::Path(path::Error)`.
A too-long path still maps to `BoundsExceeded`, so no wire code changes.
moq-rtc answers an invalid WHIP/WHEP path through its own `Error::InvalidPath`
instead of matching moq-net variants, which also makes a too-long path a 400.
- `auth::Handle::add` returns the `Credential` alone; `auth::Answer` is private.
- `auth::Request::{kind, path}` are removed and `auth::RequestKind` is private.
- `auth::Tokens::{dial, connected, changed}` and `auth::Dial` are crate-private.
- `Session::poll_idle` is crate-private and loses its `idle` wrapper; its
integration tests move into a unit test.
- `Version::has_setup_token`, `track::Producer::abort_unwanted`,
`datagram::{Producer, Consumer}::is_clone`, `datagram::Info::produce`, and
`stats::Activity::WINDOW` are crate-private; `socket::Dialing::session` is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`PeerGrant`, `Key`/`KeySet::{sign_peer, verify_peer}`, `KeySet::to_peer_set`,
and `Error::{NoPeerKey, PrivatePresenter}` had no consumer: P2P trusts its
peers, so relay-issued peer grants wait for a real per-peer scope use case.
Removes the "Peer grants" doc section and the quest that planned this.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ADME # Conflicts: # quest/m3/release/npm-first-publish.md
…er events
- MoqFill::{start_group, start_frame, end_group} are start() -> MoqPosition and
end(), like track::Fill.
- MoqTrackRequest::abort and MoqDatagramRequest::abort are reject, like
track::Request and datagram::Request.
- Go GrantConsumer and BandwidthConsumer Close is Cancel, like every other
Go stream handle.
- Python and Go JSON window events are WindowEventPush/Pop/Skip, and Go's
TimedWindowEvent is WindowTimed, matching Kotlin and Dart.
- Python and Swift VideoInit carry the lower rendition as a wrapper producer,
as Go's does, so TrackProducer.video and TrackStreamProducer.video drop
their separate lower argument.
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>
The pass budget was public only for the worker_turns 1-versus-4 sweep. Four is the value #7530 chose from its 1/2/4/8 sweep, and its ablation showed one pass splitting each wake chain across turns. The finished API audit epic is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ADME # Conflicts: # js/qmux/src/index.ts # js/qmux/src/session.ts
There was a problem hiding this comment.
ℹ️ No code findings. A handful of prose references still name surfaces this PR removes, including MIGRATE lines the Impact list for the cut does not mention.
Reviewed changes
- JS:
Frame.{Info,Producer,Consumer}split out ofGroup,socket→Socket,Catalog.Audio/Videoreduced torankedwith flat config types, andReport.PRIORITY,Writer.wanted,DEFAULT_MAX_BUFFER,IMPLEMENTATION,Path.MAX_BYTES,LatencyEntrySchema,Fanout's constructor/close,Datagram.Request, andSession.streamCreditunexported or@internal. - Rust net/auth/crypto:
moq_net::Datagramgiven one path,Error::Path(path::Error),Handle::addreturning onlyCredential, andAnswer/RequestKind/Request::{kind,path}/Tokens::{dial,connected,changed}/Session::{idle,poll_idle}/Activity::WINDOW/datagram::Info::producenarrowed or removed; the peer-grant API deleted with its quest. - Transport/relay: moq-quic reduced to one path per type with its event stream removed,
Bbr3/Cubicand the pacing-rate knob privatized or deleted,moq-sockdemux internals andmoq-relay'suringmodule privatized, tokio listeneracceptreturningResult, andmoq-uring's pass budget fixed at four. - Media/gateways:
Catalog::without_ext(),with_delay/with_latency/with_cmafrenames, and the mux/HLS/stats buffer, limit, and aggregate-reader knobs privatized. - Bindings:
Fill.start()/end()and requestrejectmirrored through moq-ffi, Go, Python, and Swift, with Python/SwiftVideoInitwrappers soloweris set once. - Quests: the epic deleted, its two citers pointed at a pinned revision, and
@moq/uiadded to the m3 npm first-publish quest.
ℹ️ Stale references to the APIs this PR removes
The Impact section's "Stale MIGRATE.md lines the release cut should fix" list is what the cut relies on, and it misses three files whose content this PR invalidates; two more prose references name a removed method.
Technical details
# Stale references after the removals
## Affected sites
- `rs/moq-relay/MIGRATE.md:139-141,251-253` — still tell embedders to use `uring::Workers::spawn`/
`serve`/`bind`, but `moq_relay::uring` is now `pub(crate)`; §"io_uring workers start serving
separately" and §"Embedding: io_uring workers bind from the server config" need dropping or
rewriting to the public `Relay`/`Web` path.
- `rs/moq-quic/MIGRATE.md:44,52` — the migration table maps `Event::HandshakeConfirmed` and
`StreamEvent::Acked` to `Connection::poll_handshake_confirmed` and `send::Stream::poll_acked`,
which this PR makes `#[cfg(test)]`; the surviving answers are `poll_connected` and
`Stream::acked`.
- `rs/moq-quic/README.md:87` — the "ACK progress" bullet still lists `poll_acked` as a wait API;
the "Waits" bullet in the same file was updated to drop it.
- `rs/moq-net/MIGRATE.md:17,269` — names `Activity::WINDOW` (now private) and
`Error::EmptySegment` (now `Error::Path(path::Error::EmptySegment)`).
- `rs/moq-net/src/session.rs:1018` — `[`Session::idle`]` is now a broken link; the method is
`Session::poll_idle`, and is private.
- `quest/m3/goaway-migration-followups.md:9` — the JS early-close follow-up says "mirroring
`Session::idle` / `Session::poll_idle`"; only `poll_idle` remains.
## Required outcome
- The Impact's stale-MIGRATE list covers every MIGRATE line this PR invalidates.
- No in-tree doc or quest names an item this PR removed or made private.deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit 9aa0ce3 against base 1a1940c. No actionable correctness findings in the changes inspected.
Focused on the JS frame extraction and import dependencies; auth request/grant handling and path-error mappings; FFI and language-wrapper API migrations; CMAF/latency/delay option plumbing; and transport surface removal. The frame implementation is preserved through the move, removed PathUpdated events were discarded by both runtime drivers, and Limits.send_rate remains enforced independently of the congestion pacer. The intentional breaking changes and documented maintainer decisions were treated as the agreed scope.
Verification limits: GitHub-only static review. I did not run builds, tests, Swift/browser checks, interop, or benchmarks, and did not independently repeat the full public-API census or external downstream searches. The exact-head Check workflow is still in progress: https://github.com/moq-dev/moq/actions/runs/42325488378. This is not runtime validation or merge approval.
(Written by review (OpenAI))
# Conflicts: # doc/lib/js/net.md # js/net/src/internal.ts # js/net/src/socket.test.ts
It fails on main too when the host is loaded: the client's 100ms wall-clock timeout fires and the server's accept unwraps ConnectionClosed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s-2 epic Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 head 51747bb against base c02ace3, incrementally since d804085 and accounting for merged main changes.
No new actionable findings. The production API changes remain equivalent to the prior review. Socket conflict resolutions preserve main's client/server roles and stream-error imports under the Frame/Socket names, including its new origin-close test. The epic and reference removals now follow the last child's merge in #8121. The new stream_stopped quarantine has the matching inventory entry; its existing 100 ms client deadline is consistent with the documented load-sensitive failure.
Direction: retain the migration guidance and complete the quarantined test's causal fix. This pass does not repeat the API census or certify every surface added on main.
Verification limits: GitHub-only base-aware comparison of all 206 old and 212 new file patches, with focused merge-resolution, quest and test inspection. No builds, tests, Swift/browser checks, interop, benchmarks or downstream searches run.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Since the previous pullfrog review at 1fa13412b1:
- Quarantined the flaky
stream_stoppedtest:moq-tokio'squic::driver::tests::stream_stoppedis now#[ignore]d (its 100ms wall-clock budget flakes under load and it fails onmaintoo), with ash/gh/test-inventory.allowentry namingquest/m0/test-flakes-2/README.md. - Merged
origin/main(c02ace3017, conflict-free): brings #8115 socket roles, #7670 skip/stale drops, #8150's lite-07 quarantine, #8157, #8167, #8162, #8140, #8081, and the quest updates; the branch'sSocket/Framerenames and API-audit removals are preserved. - Dropped a doubled blank line in the allowlist.
deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏
…ADME # Conflicts: # quest/m1/README.md # quest/m2/recut-held.md # sh/gh/test-inventory.allow
Fix or clarify each automated review finding on the sweep's quest edits, and fold #8088's with_proxy follow-up into api-shape/net. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#8088 narrowed it to private; the corpus test signs raw payloads with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

The final pass of the API audit epic (
quest/m1/api-audit/README.md), which finishes it: its last child landed in moq-dev/moq#8121, so this PR deletes the epic. I diffedmain's public API againstrelease's and the audit base, then made private, removed, or renamed each surface added since the audit that breaks the epic's rules. The maintainer answered the five open decisions on 2026-11-06; they are recorded below.Maintainer decisions (2026-11-06)
Kept public: the m3 realtime-uplink bake-off surfaces,
moq_congestion::{gcc, scream}, moq-tokio'squic::Controllerhook (Config.controller,Resolved.controller,has_controller,moq_tokio::congestion), and moq-quic'stransport::Config.receive_timestamps.Kept public: all of
moq_crypto::sign, signing included, for the m3 plans. Not chosen: removing signing.The
quic::weberrors become one typedweb::Errorper crate in moq-tokio and moq-uring, not in this PR. moq-dev/moq#8167 landed it.Kept public: moq-stats'
aggregate::{Consumer::group, GroupConsumer}andgroup_track.Made private in this PR, at a fixed value:
moq_uring::Config.passes, the per-turn task pass budget. It is fixed at 4, the default since moq-dev/moq#7530. That PR chose four from a joint sweep of 1, 2, 4, and 8 passes, where eight found no additional chat work. Its 1-versus-4 ablation onworker_turns(release profile, repeated A/A) showed one pass splitting each wake chain across turns:I found no nightly results that contradict it. The field is now
pub(crate)so the in-crate 1/2/4/8 hand-off test still sweeps it, andworker_turnsdrops its passes axis.Also dropped: the follow-up to make moq-relay's
Webbuilder private. The maintainer decided on moq-dev/moq#8082 to keep one publicWeb::with_listensetter.How the audit ran
release(a005c7a), the audit base (d44813c), andmain(f2f9bc9):--all-features, walked from each crate root. Unpublished and demo crates are excluded, and crate renames are normalized (moq-clock tokio::clock, moq-e2ee tomoq_crypto::e2ee,moq_quic::congestionto moq-congestion).exports.mainbut absent from bothreleaseand the base. Seven read-only reviewers (JS core, JS media, JS player, Rust net, transport, media, bindings) judged each cluster against the epic's rules. They searched for consumers in this repository, moq.pro, moq.dev, and studio atorigin/main, plus m1/m2 quests.mainagainst 20,065 onrelease, and JS had 4,114 keys against 3,936. Most of the growth is new crates and features (moq-quic's public API, qmux, moq-congestion, moq-crypto,@moq/ui), not duplicated surface.Changes
JS
@internal:Report.PRIORITY,Report.Writer.wanted,ConsumerProps.maxBuffer,DEFAULT_MAX_BUFFER,LatencyEntrySchema,createFullscreen,Fullscreen,GraphOptions.{max, samples},FanoutProps,Fanout's constructor andclose,Broadcast.STATS_TRACK,Datagram.Request,IMPLEMENTATION, andPath.MAX_BYTES.Session.streamCreditandStreamCreditfrom@moq/qmux. The maintainer reversed the transport credit API in moq-dev/moq#7894.Catalog.AudioandCatalog.Videoexport onlyranked.Group.Frame{Info, Producer, Consumer}becameFrame.{Info, Producer, Consumer}.Moq.socketbecameMoq.Socket.readonly:<moq-watch>connection,emitter,text, andtextRenderer, and<moq-publish>connection,broadcast,video, andaudio.Rust net, auth, crypto
moq_net::Datagramlost its root re-export, so the type now has one path.Error::{EmptySegment, InvalidEscape}becameError::Path(path::Error). Error codes are unchanged, and moq-webrtc maps a bad path to 400 without matching on moq-net errors.Handle::addreturns only theCredential.Tokens::{dial, connected, changed},auth::Dial,auth::Request::{kind, path},RequestKind,Answer,Session::{poll_idle, idle},Version::has_setup_token,track::Producer::abort_unwanted,datagram::Info::produce, datagramis_clone,socket::Dialing::session, andstats::Activity::WINDOW.PeerGrant,sign_peer,verify_peer,to_peer_set, and two error variants), and deleted the quest that planned it,quest/m4/auth-drop-peer-grant.md.Transport and relay
sendandrecvat the root; the stats types,Streams, andDatagramsunderconnection::.connection::EventandConnection::poll.transport::Config.max_outgoing_bytes_per_second, which overlappedLimits.send_rate, along with theInit.max_pacing_rateit fed.poll_ackedandpoll_handshake_confirmed.demux::{classify, Class, Queue::SHARE}.uringmodule.listen::Forward::configured.Bbr3andCubic. Its root re-exports are removed.Config.passesis private, fixed at four (maintainer decision 5).--listen-implementationand--connect-backoff-healthyare code-only now, matchingconnect.implementation.tcp::Listener::acceptandwebsocket::Listener::acceptreturnResultinstead of theOption<Result>that their docs said was kept only for compatibility.Media and gateways
Catalog::media()is nowwithout_ext(), sinceCatalog.mediais the media section.with_max_delayis nowwith_delay.with_max_delayis nowwith_latency, itsreleasename.with_passthrough/passthroughare nowwith_cmaf/cmaf, matching the CLI's--cmaf.Consumer::set_max_buffer,DEFAULT_MAX_BUFFER, andfmp4::MAX_*.consume::{Consumer::group, GroupConsumer}.Broadcaster::is_cloneandRendition::{interval, segment_length}.moq auth serve --mtls-peer/--mtls-upstreamrefusals. Those spellings never shipped inrelease.Bindings
MoqFill::{start_group, start_frame, end_group}becamestart() -> MoqPositionandend(), mirroringtrack::Fill.MoqTrackRequest::abortandMoqDatagramRequest::abortbecamereject.GrantConsumer.CloseandBandwidthConsumer.ClosebecameCancel.WindowEvent{Push, Pop, Skip}, and Go'sTimedWindowEventis nowWindowTimed.VideoInit, as Go does, soloweris set once.Quests
quest/m3/release/npm-first-publish.mdnow includes@moq/ui, whichnpm viewstill returns 404 for and which@moq/watchand@moq/publishdepend on.quest/m1/api-audit/README.mdwithquest rm, along with itsRequiredentries in m1 and m2 and its prose mentions inquest/m1/README.md,quest/m2/recut-held.md, andquest/m2/group-drops.md. Its last child,join.md, landed in moq-dev/moq#8121.Surfaces
mainadded since the audit's headMerging
origin/main(142b03b) brought in new public API since the reviewed head 9aa0ce3. Each item was checked against the epic's rules. None breaks them, so this merge changes none:@moq/netTrack.Consumer.{floor, start, nextInRange}(moq-dev/moq#8071):@moq/hang's container reader calls all three, and each mirrors a RustSubscribermethod (floor,poll_start,next_in_range). RustSubscriber::poll_startis new too; moq-mux's container consumer calls it.@moq/qmuxConfig.handshakeTimeout(moq-dev/moq#8054): mirrors Rust qmux'sConfig.handshake_timeout, next toidleTimeout. qmux's wsconnect/acceptbecame async in the same PR, with no new surface.Server::accept_withandClient::connect_with(moq-dev/moq#8085): the WebRTC transport calls them, andquest/m2/webrtc-rename.mdmoves it to moq-webrtc. The session-policy quest checked them against this epic's consumer rule.Incomingispub(crate).playback::Observation.comfort(moq-dev/moq#8055): moq-cli's play metrics report it.Export::newandRelease::newtake the delay positionally (moq-dev/moq#7981), replacingwith_delay. That PR narrowed the surface itself.@moq/watchVideo.SourceInput.ratereplacesprobe(moq-dev/moq#8061).Merging
origin/mainagain (c02ace3) brought more new public API. None breaks the epic's rules, so this merge changes none:@moq/netTrack.Producer.skipGroupsandError.Skipped(moq-dev/moq#7670): they mirror Rusttrack::Producer::skip_groupsandError::Skipped. moq-archive, moq-c, and moq-ffi callskip_groups.codec::h265::{Sps, VideoSignal}(moq-dev/moq#8140): moq-video's VUI decode callsSps::parse.NalTypeispub(crate).clock::host_time(moq-dev/moq#8081): tests and binaries that need the host clock call it.quic::web::Error(moq-dev/moq#8167): maintainer decision 3.pubitems. Its JS side now uses this PR'sSocketname.Merging
origin/maina third time (6f66d55) brought more new public API. None breaks the epic's rules, so this merge changes none:set_panandpan(moq-dev/moq#8180): a new mixer feature, next to the strip's gain controls.origin::Producer::with_proxyandorigin::Consumer::with_proxy(moq-dev/moq#8023): moq-relay's cluster, moq-stats, and tests call the Producer one. Only tests call the Consumer override, so it is a suggested follow-up below. The route layer itself (route::Nodeand friends) stays crate-private.APP_LIMITED_MASK(moq-dev/moq#8170) is inside a private module.Merging
origin/maina fourth time (181e8bb) brought no new public API, so this merge changes none:vendormodule (str0mis onlypub(crate)in it), so no public item exposes a vendored type and str0m left the dependency graph. That narrows moq-webrtc's public dependencies.Kept public on purpose
moq_crypto::sign(maintainer, 2026-11-06, above).moq_auth::meshClient,Signer, and the coordinator handlers (decided 2026-11-02).aec(moq-dev/moq#7369).Snapshot.Config.maxGroupBytes(moq-dev/moq#7072).@moq/hangHealth, which moq.pro's m2 qos quests plan to consume.@moq/watchBroadcast.include(decided 2026-11-04).MoqTrackInfo.{max_age, max_age_unlimited}: UniFFI 0.32 can't give aDurationa zero default.moq_net::{Reconnect, Server, Session}root re-exports: one pattern, so all or none.Refuted findings:
moq_json::window::Producer::abortand its JS mirror: moq-c and moq-ffi call it.bandwidth::DemandandProducer::demand: moq-tokio'sRecvBandwidthuses them.transport::StreamCredit: moq-net's open line uses it.In-flight PRs
with_passthroughcallers needwith_cmaf.rejectandFillrenames. rs/moq-c was left to it.setCost,RouteInfo.hops,cost).send::Stream::acked, which stays public.Impact
Public API: breaking in every area listed under Changes. Wire: none; error codes and session codes are unchanged.
Migration notes:
Report.PRIORITY: removed.Report.Writer.wanted: removed; usewriter.track.demand().wanted.Container.DEFAULT_MAX_BUFFER: removed.maxBufferis internal.Catalog.Audio.{Audio, AudioConfig, AudioSchema, AudioConfigSchema}andCatalog.Video.*: use the flatCatalog.*names.rankedis unchanged.LatencyEntrySchema: removed. TheLatencyEntrytype stays.createFullscreenandFullscreen: removed; usefullscreenButton.GraphOptions.{max, samples}: removed.Fanoutis type-only and has noclose().FanoutProps: removed.Broadcast.STATS_TRACK: removed; readcatalog.stats.track.readonly.Session.streamCreditandStreamCredit: removed.Datagram.Request: removed.Group.Frame{Info, Producer, Consumer}->Frame.{Info, Producer, Consumer}.socket->Socket.IMPLEMENTATION: removed; pass your ownimplementation.Path.MAX_BYTES: removed (4096).moq_net::Datagram->moq_net::datagram::Datagram.Error::{EmptySegment, InvalidEscape}->Error::Path(path::Error::{EmptySegment, InvalidEscape}).auth::Handle::add(t).awaitreturnsCredential.auth::Answer: removed.auth::Request::{kind, path}andRequestKind: removed.auth::Tokens::{dial, connected, changed}andauth::Dial: removed; useReconnect::with_tokens.Session::{poll_idle, idle},Version::has_setup_token,track::Producer::abort_unwanted,datagram::{Producer, Consumer}::is_clone,socket::Dialing::session, andstats::Activity::WINDOW.datagram::Info::produce: removed; usebroadcast.create_datagrams(name, info).PeerGrant,Key/KeySet::{sign_peer, verify_peer},KeySet::to_peer_set, andError::{NoPeerKey, PrivatePresenter}.ErrorgainsInvalidPath.moq_quic::{CreditStats, FrameStats, PathStats, UdpStats, Streams, Datagrams}->moq_quic::connection::*.connection::{send, recv}->moq_quic::{send, recv}.EventandConnection::poll: removed.transport::Config.max_outgoing_bytes_per_second: removed; useLimits.send_rate.send::Stream::poll_ackedandConnection::poll_handshake_confirmed: removed; useacked.Init.max_pacing_rate: removed.moq_congestion::{Gcc, Scream}->gcc::Gccandscream::Scream.{Bbr3, Cubic}: removed; usebbr3::Configandcubic::ConfigthroughFactory::build.moq_tokio::quic::driver::{CreditStats, FrameStats, PathStats, UdpStats}->moq_quic::connection::*.tcp::Listener::acceptandwebsocket::Listener::acceptreturnResult<Session>.--listen-implementation/MOQ_LISTEN_IMPLEMENTATION/listen.implementation: setlisten::Config.implementationin code.--connect-backoff-healthy/MOQ_CONNECT_BACKOFF_HEALTHY/connect.backoff.healthy: setBackoff.healthyin code.listen::Forward::configured: removed.demux::{classify, Class}andQueue::SHARE: removed.Config.passes: removed; a turn runs at most four task passes.uringmodule: removed.Catalog::media()->Catalog::without_ext().Client::with_max_delayandPlay::with_max_delay->with_delay.Client::with_max_delay->with_latency, the same asrelease.fmp4::Import::with_passthrough->with_cmaf.container::Consumer::set_max_bufferandDEFAULT_MAX_BUFFER: removed.fmp4::{MAX_HELD_BYTES, MAX_METADATA_BYTES, MAX_FRAGMENT_SAMPLES, MAX_TRACKS}: removed; the limits are documented onImport::decodeandfmp4::Error.import::Config::passthrough->cmaf.export::Broadcaster::is_clone: removed.Rendition::{interval, segment_length}: removed; readmedia.join.interval.consume::{Consumer::group, GroupConsumer}: removed; subscribe togroup_track(..)and decodeGroupFrame.auth serve --mtls-peer/--mtls-upstream: removed; use--mtls-link peer|upstream.MoqFill.start_group()/start_frame()->start().group/start().frame, andend_group()->end(). Python:fill.start.group. Go:Start().Group. Swift:start.group.MoqTrackRequest.abortandMoqDatagramRequest.abort->reject. Go:Abort->Reject.GrantConsumer.CloseandBandwidthConsumer.Close->Cancel.json.WindowPush/Pop/Skip->WindowEventPush/Pop/Skip, andTimedWindowEvent->WindowTimed.moq.json.WindowPush/Pop/Skip->WindowEventPush/Pop/Skip.TrackProducer.video(b, init, lower=p)->video(b, VideoInit(..., lower=p)), and the same forTrackStreamProducer.video(broadcast:initData:target:lower:)->VideoInit(..., lower: .track(p)).Stale
MIGRATE.mdlines the release cut should fix (only the cut edits them):rs/moq-rtmp/MIGRATE.md:42,54,55->with_delay.rs/moq-srt/MIGRATE.md:36: drop it, since the name is back towith_latency.rs/moq-hls/MIGRATE.md:46,59,128.rs/moq-mux/MIGRATE.md:207->.with_cmaf(true).rs/moq-cli/MIGRATE.md:34->--cmaf.rs/moq-relay/MIGRATE.md:121->--mtls-link peer.Downstream code that breaks on the next bump:
rs/edge/src/rtmp/mod.rs:456and:864:with_max_delay->with_delay.agent/tests/test_voice.py:764,767andagent/tests/test_voice_session.py:179:moq.json.WindowPush->WindowEventPush.Choices made without asking
Fanoutis exported as a type only. A@internalconstructor fails the repository's constructor check, andvideo/capture.tssubclasses it.Backoff.healthystays as a code-only field rather than being deleted. The reconnect integration tests need a sub-100ms healthy bar.RenditionStatsinto hangStats.Rendition: the hang schema'su53brand doesn't match the encoders' plain numbers (suggested follow-up).max_age: UniFFI limits make it impossible (recorded above).stream_stoppedis quarantined (see Validation). Itssh/gh/test-inventory.allowentry names the existing m0 epicquest/m0/test-flakes-2/README.mdas the owner, since the inventory requires an owning quest and only/quest-plancreates one. The follow-up below gives it its own child.Validation
This round merged
origin/mainthree times, up to c02ace3, which includes the queue's conflict at 17:50 UTC.Latest iterate: merged
origin/main181e8bb into 2ee2cc4 as ae8d2bd. Only the quest link list inquest/m4/README.mdconflicted, and the localquestmerge driver resolved it.git diff origin/main...HEADdiffers from the reviewed head's diff only in index hashes, hunk offsets, and context lines.quest checkpasses, andquest gate just cipassed every lane on ae8d2bd (Swift skipped as below).Previous iterate: merged
origin/main6f66d55 into 2ee2cc4. The conflicts were in quest prose only (quest/m1/README.mdandquest/m2/recut-held.mdnow drop both api-audit and the finished session-policy from the held list) and insh/gh/test-inventory.allow, which keeps main'slite_tracks_interopentry and this PR'sstream_stoppedquarantine. Outside those lines,git diff origin/main...HEADmatches the reviewed head's diff.quest check --fixpasses, andquest gate just cipassed every lane on 2ee2cc4 (Swift skipped as below). Main has since added d389cfb (#8185), which merges conflict-free.doc/lib/js/net.md,js/net/src/internal.ts, andjs/net/src/socket.test.ts. The resolution keeps main's socket server and client roles (moq-dev/moq#8115) and stream-error imports, under this PR'sSocketandFramenames.quic::driver::tests::stream_stoppedfailed the land fixer'sjust ci base, and it fails onmaintoo. The client side has a 100ms wall-clocktimeout. When that fires, it drops the connection, and the server's accept unwrap attests.rs:1684panics onConnectionClosed(APPLICATION_ERROR).cargo nextest run --stress-count 500on a quiet host. Pinned to one core with 40 busy loops, 30 of 30 failed with that panic.mainc3f5a1b, under the same contention: 28 of 30 failed, and 20 of 20 quiet runs passed.#[ignore]d and listed insh/gh/test-inventory.allow. The fix is a suggested follow-up.quest gate nix develop --command just ci origin/mainran twice:check gh. Its test inventory required an owning quest for the new#[ignore]. The allowlist entry fixes that, andsh/gh/test-inventory.pynow passes.test rs(11,532 passed, 148 skipped), excepttest js. That failure was the@moq/nettest "integration: lite-07 reports a relative start over a frameless newest group", which predates this PR. The fulljs/netsuite (bun run test) failed it in 1 of 5 runs here and 2 of 10 onmain31f19c7. Alone it passes 300 of 300. moq-dev/moq#8185 quarantines it.Checkon the old head 1fa1341 failed only "lite-07 answers a bounded window that resolves empty and FINs in reply". Withbun test --rerun-each 300, it failed 18 of 300 times on both this branch andmain. moq-dev/moq#8150 quarantined it, and that fix is merged in here.sh/gh/test-inventory.pyandquest check --fixpass.just ciprints "swift check: no swift toolchain on PATH, skipping", since this host has no macOS toolchain, and PR CI doesn't run Swift either. The SwiftFill/rejectrenames and theVideoInitwrapper need macOS. Suggest dispatchinggh workflow run platform.yml --repo moq-dev/moq --ref quest/m1/api-audit/READMEbefore landing.just test harness, the Playwright/Chromium/Firefox suites,just bench-browser, the browser media rows (just test media), and interop'sjsbrowser client.Earlier runs, on 9aa0ce3:
just check origin/mainon the merged head (twice, the second time after the passes change and a freshmainmerge): every lane passed excepttest rs. Its one failure wasmoq-relay uring::tests::a_group_stopped_before_serving_joins: io_uring setup hit the per-userRLIMIT_MEMLOCK(8 MiB) that every process on this busy host shares. The second run also hit it inpending_admission_is_abandoned_at_the_deadline. A serialcargo nextest run -p moq-relay -p moq-uring --all-features --test-threads 1 --no-fail-fast -E 'test(/uring/) | package(moq-uring)'passed 184 of 184 on the branch, as it did onmain.just checkpassed on its own branch.just test interop --all --publishers rust,python,go,cpp --subscribers rust,python,go,cpp,js-native-node,js-native-bun,c,gst: all 182 rows passed, after fixing the Go interop client's stalegrants.Close. This is the full matrix minus the browserjsclient.Suggested follow-ups
@moq/publishRendition.statsas hang'sStats.Rendition: letReport.Writertake its schema's input type, or drop theu53brand from the stats schemas.quic::driver::tests::stream_stoppedat its cause and un-ignore it, as a child ofquest/m0/test-flakes-2. It bounds the client with a 100ms wall-clocktimeout, so a loaded host fails it, while nextest's 60sterminate-afteralready bounds a hang. The likely fix is to drop that timeout, or assert on the stopped event instead of a deadline.origin::Consumer::with_proxy(moq-dev/moq#8023) in favor ofProducer::with_proxy, which already reaches every consumer taken from it. Only tests call the Consumer override, but the moq-net harness passes it about 195 scoped consumers, so collapsing it is its own change. Recommend planning it under this epic's successor.endpoint::{Accepting, Accepted},start_accept/finish_accept,Connection::{side, is_handshaking}, andstream::Id::{new, dir, initiator}.MoqRoute.instanceId()andMoqAudioEncoderFinishedonce moq moves to rust2's UniFFI fork (quest/m3/c).Review
Rewritten by
quest reviewafter each round.01a1b827-845d-7160-85fc-3f14ecc2a146, round 1Source review found no actionable behavioral regressions in the scoped changes; builds and tests were not run, as instructed.ae8d2bd only merges
origin/main181e8bb into the reviewed head 2ee2cc4. Itsgit diff origin/main...HEADmatches the reviewed head's diff apart from context and offsets, so this review covers it.The first attempt to resume the previous session failed (
questasked it to settle findings from a clean round), so this round started a new session with--new.Pullfrog's review of 1fa1341 found PR-body claims that predated the epic's deletion, plus the moq-rtc to moq-webrtc rename. Fixed in this body.
🤖 Generated with Claude Code
(Written by Claude Opus 5.5)