MoQT Implementation Status

August 9, 2026 · View on GitHub

Tracks this codebase's implementation of draft-ietf-moq-transport-19 (plus -loc-04 and -msf-01 at the edges).

Overall: ~97% complete

The wire codec, all control messages and parameters, data streams/datagrams, the session lifecycle, and the relay are implemented and wired end to end. What remains is intentionally out of scope: behaviour the draft delegates to the transport (congestion control, 0-RTT, communication/media security) and global cross-session resource quotas, which sit above this library (per-session caps and the Authorizer hook are the in-library surface).

How the number is derived. Each trackable feature below is scored DONE = 1, PARTIAL = 0.5, MISSING = 0. Items the spec explicitly delegates to QUIC/TLS or to deployment policy (most of §13) are scored on their hook/ surface-area completeness, not as protocol obligations. Legend:

  • DONE — wire codec + session/relay behaviour both present and wired.
  • PARTIAL — present but incomplete; see note.
  • MISSING — not implemented.
  • N/A (transport) — handled by the underlying QUIC/WebTransport stack.

What's implemented

By package, bottom-up along the dependency stack:

  • wire — byte-level codec: §1.4.1 leading-ones varints (distinct from QUIC's RFC 9000 varints), length-prefixed bytes, delta-encoded KV pairs (§1.4.3), track namespaces, reason phrases; an in-memory Reader and a streaming Decoder over one control-frame interface.
  • message — typed control, request-stream, and data-stream messages with parameter negotiation: SETUP, GOAWAY, SUBSCRIBE, PUBLISH (+DONE/SKIPPED), FETCH (standalone + relative/absolute joining), TRACK_STATUS, REQUEST_UPDATE, the namespace messages, §11 object framing (subgroup/fetch/datagram), location filters, GREASE, and a parse-time Validate hook that rejects structurally-malformed messages.
  • session — the SETUP handshake with version negotiation, control multiplexing and request-ID allocation, §3.5 Track-Alias management with collision detection, the request openers (Publish/Subscribe/Fetch/…) and the AcceptRequest responder, typed inbound data streams that resolve §11.4.2/§11.4.4 deltas to absolute IDs, GOAWAY, the §10.20 token cache, and pluggable transport via the Conn interface (quicconn + wtconn adapters).
  • locObject.Encode/Decode: typed Timestamp/Timescale/VideoConfig/ VideoFrameMarking/AudioConfig/AudioLevel properties with Extras passthrough for unknown IDs, an RFC 6464 audio-level codec, and AVC/HEVC NAL framing detection.
  • msfCatalog/Track JSON (independent and delta catalogs, with Apply replaying delta operations in document order), group-ID sequencing, the Media and Event Timeline record formats, the BeginBroadcast/ EndBroadcast* workflow helpers, and Catalog.Validate.
  • relay — routes objects through a track registry with per-subscription live fanout under a §8 slow-reader policy, merges multiple upstream publishers per track (§9.5) with §2.1 {Group, Object} dedup and survivor-continues failover, serves FETCHes from a per-track cache (stitching evicted ranges from an upstream FETCH), issues on-demand upstream SUBSCRIBEs to every matching publisher (local and, via a DiscoveryStore + Dialer, remote), reflects remote namespaces to local subscribers, gates requests through an Authorizer hook, emits telemetry through a Metrics hook, and drains sessions with GOAWAY.

§1.4 Foundational structures

§FeatureStatusNotes
1.4.1Variable-length integersDONELeading-ones encoding (§1.4.1, NOT QUIC's RFC 9000 varint) in wire.AppendVarint/ParseVarint/ReadVarint; used by wire.Reader/Writer/StreamReader.Varint.
1.4.2Location structureDONEmessage.Location with Compare/Less; KindLocation param serialization.
1.4.3Key-Value-Pair structureDONEwire.KVPair; even=varint / odd=length-prefixed; 0xFFFF cap, delta-overflow check.
1.4.4Reason phrase structureDONEwire.*.ReasonPhrase; 1024-byte max enforced.
1.5Namespace / track name encodingDONEwire.TrackNamespace; serialized-name parsing.

§3 Sessions

§FeatureStatusNotes
3.1Session establishmentDONESETUP handshake in handshake.go.
3.1.1MOQT URI schemeDONEpkg/moqt/uri parses/validates moqt:// (scheme, non-empty host, default port 443, well-known, https conversion); msfdemo -addr accepts a URI and feeds AUTHORITY/PATH options.
3.1.2Fragment identifiers (#type:value)DONEuri.Parse validates the type:value grammar (type ∈ [a-z0-9-]); fragment is kept local and dropped from the https URL.
3.1.3Dereferencing a MOQT URIDONEA client offers either mapping's ALPN and the server picks: relaynet.Listen advertises moqt-NN + h3 on one socket and dispatches on the negotiated protocol; uri.HTTPSURL derives the https form; cmd/interop-client switches adapter on the URL scheme.
3.1.4WebTransportDONEwtconn adapter (webtransport-go); MOQT identifiers offered as the WebTransport sub-protocol both ways.
3.1.5Native QUICDONEquicconn adapter (quic-go).
3.1.6Connection URLDONEDescriptive: a track MAY have connection URLs, and the section defers their syntax and setup to the transport mapping — which §3.1.3-3.1.5 above implement. Nothing further is required of an endpoint.
3.2Extension negotiationDONESETUP options exchanged as KV pairs; peer options parsed.
3.2.1Reserved namespacesDONEAcceptRequest rejects an exact . first field with DOES_NOT_EXIST; other .-prefixed namespaces pass through to the application per spec.
3.2.2Session-level tracks/namespacesDONE.session requests are rejected with DOES_NOT_EXIST before the application/relay sees them (no session-level extensions implemented), so relays never forward them; covers the empty-track-name rule.
3.3Session initializationPARTIALControl streams + SETUP exchange; early data-stream buffering. A bidi stream opening with an unexpected message type resets that stream instead of closing the session with PROTOCOL_VIOLATION as §3.3 requires — see Limitations.
3.3.2Request cancellation / rejectionDONESTOP_SENDING, stream resets, REQUEST_ERROR in request.go.
3.3.3Stream reset error codesDONEAll codes in errors.go (StreamReset*).
3.4Unidirectional stream typesDONESUBGROUP / FETCH / PADDING / SETUP type IDs dispatched.
3.5TerminationDONESession error codes; Close() sends CONNECTION_CLOSE w/ reason.
3.6Migration (GOAWAY)DONESendGoaway/OnGoaway/PeerGoaway, new-session URI (draft-19 removed the Request-ID watermark field).
3.3.10-RTTN/A (transport)No app-level 0-RTT handling; QUIC stack provides it.
3.7Congestion controlN/A (transport)No app-level pacing/bufferbloat logic (§3.7.1–3).

§5 Publishing and retrieving tracks

§FeatureStatusNotes
5.1SubscriptionsDONESubscribe/Publish/OK/Error state machine in pubsub.go.
5.1.1Subscription state managementDONEREQUEST_ERROR / STOP_SENDING / PUBLISH_DONE handling + cleanup.
5.1.2Location filtersDONEAll 4 types (NextGroupStart, LargestObject, AbsoluteStart, AbsoluteRange) + Matches.
5.1.3Range filtersDONEObject filters (SUBGROUP/OBJECTID/PRIORITY/OBJECT_PROPERTY) enforced on SUBSCRIBE fanout, datagrams, and FETCH; TRACK_PROPERTY_FILTER gates PUBLISH forwarding on SUBSCRIBE_TRACKS; MAX_FILTER_RANGES/INVALID_FILTER gating in place. Two documented carve-outs (see Known protocol gaps): REQUEST_UPDATE whole-set replace vs per-type merge, and §6.3 object filters on a SUBSCRIBE_TRACKS not yet applied to the resulting subscription's objects.
5.1.4Combining filtersDONEForwardDecision ANDs Forward + Location + Range filters per object (§5.1.4); Range filters combine SetIDs via AND/OR.
5.1.5Joining an ongoing trackDONERelative & absolute joining FETCH in fetch.go.
5.1.5.1Dynamically starting new groupsDONERelay forwards a downstream NEW_GROUP_REQUEST upstream per §10.2.18: included in the on-demand upstream SUBSCRIBE (no established upstream) or sent as an upstream REQUEST_UPDATE, gated on DYNAMIC_GROUPS support, Largest-Group, and outstanding-request bookkeeping.
5.2Fetch state managementDONEStandalone + joining fetch lifecycle.

§6 Namespace discovery

§FeatureStatusNotes
6.1Subscribing to namespacesDONESubscribeNamespace / SubscribeTracks / ReadPublishSkipped.
6.2Publishing namespacesDONEPublishNamespace; NAMESPACE / NAMESPACE_DONE messages.

§7 Priorities

§FeatureStatusNotes
7.1DefinitionsDONESubscriber/publisher priority + group order modeled.
7.2Scheduling algorithmDONEEffectiveStreamPriority builds the composite session.StreamPriority (subscriber→publisher→group-order key→subgroup), covering rules 1–4; FETCH ordering is group-order + Object-ID per §10.12.3. Draft-19's datagram-wins tie-break (rule 4) holds by construction: datagrams bypass this priority key entirely and are sent as soon as ready, never queued behind a subgroup stream's priority. Transport knob is currently a no-op (quic-go exposes no per-stream priority API — quic-go#437), so the order is computed and pushed through session.PrioritizedSendStream (propagation is test-covered) but not yet enforced on the wire.
7.3Considerations for settingDONERelay honours subscriber/publisher priority on fanout.

§8 Delivery timeouts and data reliability

§FeatureStatusNotes
8Delivery timeouts / reliabilityPARTIALOBJECT/SUBGROUP delivery timeouts enforced in session/datastream_out.go; reset w/ StreamResetDeliveryTimeout. OBJECT_DELIVERY_TIMEOUT is measured per object from its receipt time (WriteObjectReceivedAt), not from stream open. WithDeliveryTimeouts takes the publisher's and subscriber's halves separately so the §12.1/§12.2 first-object override resolves within the publisher's half before DeliveryTimeouts.Effective takes the smaller of the two. The relay sources both sides — the publisher's Track Properties (decoded once onto the entry) and the subscriber's SUBSCRIBE parameters (§10.2.3/§10.2.4) — and passes them to every subgroup stream it opens downstream, resetting that stream alone with DELIVERY_TIMEOUT while the subscription continues. Not enforced on the raw Write path (no object boundaries) or inbound — see Limitations.

§9 Relays

§FeatureStatusNotes
9.1Caching relaysDONELRU+TTL object cache (cache/cache.go); updates limited to non-existence/properties.
9.2Forward handlingDONEFORWARD flag honoured; Forward=0 pauses delivery. Upstream Forward is set to 1 only when a downstream subscriber forwards, else the relay pauses it (Forward=0) and resumes on the first forwarding subscriber.
9.3Multiple publishersDONEPer-track upstreams; dedup by {GroupID, ObjectID}.
9.4Subscriber interactionsDONEUpstream subscription established before SUBSCRIBE_OK; aggregation.
9.4.1Graceful subscriber switchoverDONEGOAWAY grace period (GoawayTimeout).
9.5Publisher interactionsDONEPUBLISH_NAMESPACE / PUBLISH with prefix matching (namespace_registry.go).
9.5.1Graceful publisher switchoverDONEConcurrent upstreams + cache dedup.
9.6Relay track handlingDONEProperties captured once at track creation, forwarded opaquely.
9.7Relay object handlingDONEObjects forwarded verbatim except alias remap + Object-ID delta re-encode.

§10 Control messages

§Message / optionTypeStatusNotes
10.1Request-ID parity/monotonicityDONEEnforced in AcceptRequest (per-role parity + monotonic).
10.2Message parameters (18 types)DONEAll 18 defined with correct kinds and per-message scope; see §10.2.x below.
10.2.1Parameter scopeDONEPer-message scope validation.
10.2.2AUTHORIZATION_TOKEN0x03DONE4 alias types; session token cache resolves inbound.
10.2.3SUBGROUP_DELIVERY_TIMEOUT0x06DONE
10.2.4OBJECT_DELIVERY_TIMEOUT0x02DONE
10.2.5FILL_TIMEOUT0x0ADONE
10.2.6RENDEZVOUS_TIMEOUT0x04DONE
10.2.7SUBSCRIBER_PRIORITY0x20DONE
10.2.8GROUP_ORDER0x22DONEAscending/Descending validated.
10.2.9LOCATION_FILTER0x21DONEOverflow-checked.
10.2.10SUBGROUP_FILTER0x25DONEEnforced per object in the fanout/FETCH.
10.2.11OBJECTID_FILTER0x26DONEEnforced per object in the fanout/FETCH.
10.2.12PRIORITY_FILTER0x27DONEEnforced per object (subgroup priority); >255 rejected INVALID_FILTER.
10.2.13OBJECT_PROPERTY_FILTER0x28DONEEnforced per object against Object Properties; even property type.
10.2.14TRACK_PROPERTY_FILTER0x29DONEGates PUBLISH forwarding on SUBSCRIBE_TRACKS against Track Properties; even property type.
10.2.15EXPIRES0x08DONE
10.2.16LARGEST_OBJECT0x09DONEMonotonic constraint applied.
10.2.17FORWARD0x10DONE
10.2.18NEW_GROUP_REQUEST0x32DONE
10.2.19TRACK_NAMESPACE_PREFIX0x34DONE
10.3SETUP0x2F00DONEBidirectional handshake; options as KV pairs.
10.3.1.1AUTHORITY option0x05PARTIALSent (WithAuthority) and carried as a SETUP KV pair, but never validated on receipt: SessionInvalidAuthority is unused — see Limitations.
10.3.1.2PATH option0x01PARTIALSent (WithPath) and carried as a SETUP KV pair, but never validated on receipt: SessionInvalidPath is unused — see Limitations.
10.3.1.3MAX_AUTH_TOKEN_CACHE_SIZE0x04DONESizes the token cache.
10.3.1.4AUTHORIZATION_TOKEN (setup)0x03DONE
10.3.1.5MOQT_IMPLEMENTATION0x07DONEAdvisory.
10.3.1.6MAX_FILTER_RANGES0x06DONEWithMaxFilterRanges advertises it; relay rejects over-limit/prohibited filters with INVALID_FILTER.
10.3.1.7MAX_REQUEST_UPDATES0x08DONEWithMaxRequestUpdates advertises the per-stream limit; enforced on inbound follow-ups via RequestUpdateLimiter, closing with TOO_MANY_REQUEST_UPDATES on overflow.
10.4GOAWAY0x10DONESame encoding on control and request streams (draft-19 dropped the Request ID field); callback.
10.5REQUEST_OK0x07DONEShared OK for PUBLISH/UPDATE/TRACK_STATUS/namespace reqs.
10.6REQUEST_ERROR (+ Redirect)0x05DONERedirect required only when code==REDIRECT.
10.7SUBSCRIBE0x03DONE
10.8SUBSCRIBE_OK0x04DONERegisters inbound track alias.
10.9REQUEST_UPDATE0x02DONEA REQUEST_UPDATE opening a request stream is rejected as a PROTOCOL_VIOLATION (ErrUnexpectedRequestUpdate).
10.10PUBLISH0x1DDONE
10.11PUBLISH_DONE0x0BDONE
10.12FETCH (standalone + joining)0x16DONEAll three fetch types.
10.13FETCH_OK0x18DONE
10.14TRACK_STATUS0x0DDONEReply via REQUEST_OK.
10.15PUBLISH_NAMESPACE0x06DONE
10.16NAMESPACE0x08DONE
10.17NAMESPACE_DONE0x0EDONE
10.18SUBSCRIBE_NAMESPACE0x50DONE
10.19SUBSCRIBE_TRACKS0x51DONE§10.19.1: FORWARD/GROUP_ORDER are copied onto the PUBLISH messages the subscription triggers; an out-of-range value closes the session (§10.2.8/§10.2.17).
10.20PUBLISH_SKIPPED0x0FDONEProhibition scoped to a single PUBLISH (draft-19 §6.1) — not sticky across re-PUBLISHes.

§11 Data streams and datagrams

§FeatureStatusNotes
11.1Track aliasDONEIn subgroup header + datagram; validated.
11.2Objects / object headerDONEAll header fields encoded.
11.2.1.1Object statusDONENormal / EndOfGroup / EndOfTrack.
11.2.1.2Object propertiesDONELength-prefixed KV pairs.
11.3Object datagramDONEType bit-fields + invalid-combo rejection.
11.4Streams (subgroup / fetch)DONETyped in/out subgroup + fetch streams.
11.4.1Stream cancellationDONEBidi request-stream termination ends the request (handlers unregister on stream end); the relay sends PUBLISH_DONE on graceful subscription termination rather than abrupt reset.
11.4.2Subgroup header + delta object IDsDONEAll subgroup-ID modes; ReadDecoded resolves deltas.
11.4.3Closing subgroup streamsDONERelay forwards only the next object on a stream (gap → reset+reopen), FINs on clean inbound EOF, resets on inbound reset, resets with MALFORMED_TRACK after a terminal EndOfGroup/EndOfTrack object (§2.4.2), marks reliable boundaries for RESET_STREAM_AT (SetReliableBoundary, transport-gated on EnableStreamResetPartialDelivery), and resets (not FINs) in-flight subgroups whose group falls out of range after a narrowing REQUEST_UPDATE.
11.4.4Fetch headerDONE
11.4.4.1Fetch flagsDONEAll subgroup modes + delta/priority/properties/status flags.
11.4.4.2End of rangeDONENon-existent (0x8C) / unknown (0x10C) handled.
11.5Padding streams & datagramsDONERecognised type IDs silently discarded.

§12 MOQT properties

§PropertyTypeStatusNotes
12.1SUBGROUP_DELIVERY_TIMEOUT0x06DONETrack + Object Property; the first object of a subgroup overrides the Track-level value (§8 resolution in message.DeliveryTimeouts, enforced in OutgoingSubgroupStream).
12.2OBJECT_DELIVERY_TIMEOUT0x02DONETrack + Object Property; first-object override, as §12.1.
12.3MAX_CACHE_DURATION0x04DONELazy age-eviction in cache.
12.4DEFAULT_PUBLISHER_PRIORITY0x0EDONE
12.5DEFAULT_PUBLISHER_GROUP_ORDER0x22DONEValidated.
12.6DYNAMIC_GROUPS0x30DONEProperty defined & scope-validated (flow: see §5.1.5.1).
12.7Immutable properties0x0BDONERelays cache & forward verbatim, never add.
12.8Prior group ID gap0x3CDONEObject-scope; encoder in msf/groupid.go.
12.9Prior object ID gap0x3EDONEObject-scope.

§13 Security considerations

Most of §13 is advice the draft delegates to the transport or to deployment policy. This library provides the hooks; enforcement is the operator's.

§ConcernStatusNotes
13.1Subscription amplificationDONEConfig.MaxSubscriptionsPerSession caps concurrent subscriptions per session, rejecting excess with EXCESSIVE_LOAD before state mutation (0 = unlimited).
13.2Communication securityN/A (transport)TLS 1.3 via QUIC/WebTransport.
13.3AuthorizationDONEAuthorizer hook gates every request once before state mutation.
13.3.1Replay attacksPARTIALSession-scoped token cache; replay defence delegated to token scheme.
13.4Media securityN/APayloads opaque; E2EE (e.g. SFrame) is external.
13.5Resource exhaustionDONEQUIC flow control + slow-reader reset (fanout.go) + per-session subscription/namespace caps; the publisher cancels lowest-priority streams on overload. Global cross-session quotas remain a deployment concern.
13.6TimeoutsDONEDelivery timeouts enforced (§8).
13.6.1Idle connection handlingPARTIALKeep-alive options documented; not enforced in-library.
13.7Relay securityDONE§13.7.1: Config.MaxNamespaceRequestsPerSession bounds PUBLISH_NAMESPACE/SUBSCRIBE_NAMESPACE/SUBSCRIBE_TRACKS state per session (EXCESSIVE_LOAD). §13.7.2: the Authorizer hook gates short-prefix subscriptions.
13.8Implementation fingerprintingDONEMOQT_IMPLEMENTATION optional/configurable.

§14 Grease

§FeatureStatusNotes
14GREASEDONEIsGrease/GreaseValue/GreaseSetupOption; unknown values ignored.

Limitations

Out of scope in the relay's cross-instance routing: multi-hop loop detection (the only guard is skipping the relay's own RelayAddr), an upstream connection-health / redial policy beyond dial-on-demand, and GOAWAY cascading. cmd/relay stays single-instance by choice — the distributed DiscoveryStore backends ship as their own binaries (relay-etcd, relay-nats) in their own modules, so the core module never pulls in an etcd or NATS client.

Known protocol gaps, roughly ordered by how load-bearing they are:

  • Object Range Filters on SUBSCRIBE_TRACKS (§6.3) — the object filters (SUBGROUP/OBJECTID/PRIORITY/OBJECT_PROPERTY) that ride a SUBSCRIBE_TRACKS are parsed and validated but applied only via TRACK_PROPERTY_FILTER's PUBLISH gate; §6.3 also wants them applied to the objects of the resulting PUBLISH-created subscriptions. Object filtering on a direct SUBSCRIBE/FETCH is unaffected (fully enforced); a SUBSCRIBE_TRACKS subscriber can also restate object filters in its PUBLISH_OK, which the fanout honors.

  • Range Filter REQUEST_UPDATE semantics (§5.1.3) — updating a subscription's Range Filters mid-stream replaces the whole filter set rather than the spec's per-parameter-type replace (non-zero Length) / remove (Length 0) with untouched types preserved. So a partial REQUEST_UPDATE wipes other filter types, and a Length-0 "remove" param is rejected as INVALID_FILTER instead of removing that type. Initial SUBSCRIBE/FETCH filtering and adding filters on update work; the per-type merge is a tracked follow-up.

  • PATH / AUTHORITY are sent but never validated on receipt (§10.3.1.1, §10.3.1.2)WithPath / WithAuthority emit the SETUP parameters, but nothing checks them on the receiving side: SessionInvalidPath (0x8) and SessionInvalidAuthority (0x19) are defined in pkg/moqt/errors.go and used nowhere. Enforcement is also per transport mapping, and relaynet.Listen does not record which mapping a session arrived on (it merges both into one accept queue) — recoverable by conn type, since quicconn and wtconn are distinct implementations, but not currently carried.

  • An unexpected first message resets the stream instead of closing the session (§3.3) — "Bidirectional streams MUST NOT begin with any other message type unless negotiated. If they do, the peer MUST close the Session with a PROTOCOL_VIOLATION." The relay's OnUnknown resets that one bidi stream and keeps the session up, deliberately isolating the failure to a single request. That is friendlier, and it is not what the draft requires.

  • Delivery-timeout enforcement is outbound-only, and not on the raw path (§8) — the publisher side is wired end to end: OutgoingSubgroupStream enforces OBJECT/SUBGROUP_DELIVERY_TIMEOUT (including the §12.1/§12.2 first-object override) and the relay's fanout applies both halves to every subgroup stream it opens, sourcing the publisher's from the entry's Track Properties and the subscriber's from the SUBSCRIBE parameters. Two gaps remain. The raw Write escape hatch does not enforce OBJECT_DELIVERY_TIMEOUT at all: §8 measures it per object from that object's receipt, and a caller managing its own framing is the only party that knows either fact, so the check belongs to WriteObjectReceivedAt. And the inbound (subscriber-side) path enforces no timeout — a subscriber does not police how long the relay takes to deliver a subgroup it was promised.

    The relay's receipt time is also approximate. §8 names the first payload byte of the object; the fanout passes fwdObject.enqueuedAt, stamped once the object has been read whole, deduped and cached, so the clock starts late by the object's inbound transfer time. The error is always lenient and scales with object size. Fixing it means recording the instant in the inbound read and carrying it separately from enqueuedAt, which cannot be reused: it is the MaxFanoutLag measurement, and that window means time spent queued rather than object age.

    Note that the §3.3.4 reset codes are not interchangeable here, and the fanout keeps them apart deliberately. A delivery timeout resets the one stream with DELIVERY_TIMEOUT ("a delivery timeout was exceeded for this stream") and leaves the subscription live; only the MaxFanoutLag window uses TOO_FAR_BEHIND, whose §3.3.4 definition says the subscription "is being terminated". Collapsing the two would make a per-subgroup timeout cost the subscriber the whole track — and it is precisely the survivable variant that lets a publisher stripe sheddable data across subgroups the relay may drop under load.

  • MAX_REQUEST_UPDATES enforcement is receive-side only, and cannot trip under our own processing (§10.3.1.7) — we advertise the limit and enforce it on inbound follow-ups (RequestUpdateLimiter), but every follow-up reader (RequestBroker.Serve, the relay's per-stream loops) answers each REQUEST_UPDATE synchronously before reading the next, so a stream never holds more than one outstanding update and the check only ever fires against a peer that pipelines faster than a hypothetical async responder would drain. §10.3.1.7 explicitly permits an immediate responder not to detect such a peer. We do not self-limit outbound REQUEST_UPDATEs against a peer's advertised value for the same reason: UpdateRequest/RequestBroker.Update are synchronous write-then-read, so they never exceed any limit ≥ 1.

  • Out-of-range GROUP_ORDER on FETCH (§10.2.8) — the SUBSCRIBE and SUBSCRIBE_TRACKS paths now close the session with PROTOCOL_VIOLATION on an out-of-range GROUP_ORDER/FORWARD (§10.2.8/§10.2.17), but the FETCH paths (a FETCH REQUEST_UPDATE, and the initial standalone/joining FETCH) still scope a bad GROUP_ORDER to a REQUEST_ERROR / silent coercion pending the same promotion.

  • Late publisher pickup (§9.5) — multiple publishers per track are merged and deduplicated, but a publisher (or remote relay) that begins advertising after a track's upstream set is established is not retroactively pulled in until that set drains and a fresh SUBSCRIBE re-establishes it; publishers that PUBLISH proactively are always merged.

  • Subscriber-priority scheduling (§7.2 / §10.2.7) — fully plumbed but not enforced on the wire: the §7.2 composite key is computed (EffectiveStreamPriority) and pushed through session.PrioritizedSendStream, but quic-go and webtransport-go expose no per-stream priority API today (quic-go#437), so the bundled adapters absorb the knob and quic-go round-robins instead. A REQUEST_UPDATE that changes priority mid-stream applies only to subsequently opened subgroups.

  • LOC encryption / SecureObjects and Private Properties — intentionally out of scope pending a chosen SecureObjects revision. Some property IDs are draft-tentative (e.g. PropAudioLevel = 0x0A, pending IANA assignment).

  • MSF — no timeline GZIP compression, content protection (§4.3), token authorization, or logs/analytics. No built-in ABR helper: every catalog field a selector needs is surfaced (AltGroup, Width/Height, Bitrate, RenderGroup, Depends, TemporalID, SpatialID), but variant-selection policy is the application's job.