From ea90685a864ae46480d6eaa5501979c146964701 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 6 May 2026 17:37:02 +0000 Subject: [PATCH] revert(nests): drop moq-lite-04 ALPN advertisement (codec is wire-incompatible) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-investigation of `kixelated/moq` commit 45db108 ("moq-lite/moq-relay: hop-based clustering") revealed that Lite-04 IS wire-incompatible with our Lite-03 codec on Announce / AnnounceInterest / Probe — contradicting the earlier reasoning that motivated 4b73626. Specifically: - Announce.hops: Lite-03 writes a single varint count of hops; Lite-04 writes count + count × varint Origin ids. (`rs/moq-lite/src/lite/ announce.rs:67-73` branches on Version explicitly.) - AnnounceInterest: Lite-04 added an `exclude_hop` varint after the prefix. - Probe: Lite-04 added an `rtt` varint after `bitrate`. Subscribe / SubscribeOk / SubscribeDrop / Group / GroupHeader framing is unchanged across Lite-03↔Lite-04 — but the Announce/Probe drift alone is enough to desync a Lite-04-preferring relay if it picks `moq-lite-04` from our advertised list. We'd encode Announce hops as a bare varint where the peer expects `len + len × u62`, and the connection aborts on the first Announce exchange. Pin `wt-available-protocols` back to `["moq-lite-03"]` until `MoqLiteCodec` gains version-aware Announce / AnnounceInterest / Probe codecs and `MoqLiteAnnounce.hops` becomes a list rather than a single varint. Reverting 4b73626 — the LITE_04 constant stays in MoqLiteAlpn for documentation, but is no longer plumbed into the factory's sub-protocol list. Reverts the wire-format expansion in 4b73626. The factory and ALPN kdocs are rewritten to spell out the codec diff so the next person who considers re-enabling Lite-04 reads the actual blocker first. https://claude.ai/code/session_014JfZJHSTvyYYWJbC9VbB47 --- .../nestsclient/moq/lite/MoqLiteMessages.kt | 32 ++++++++++++++----- .../transport/QuicWebTransportFactory.kt | 28 ++++++++++------ 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/moq/lite/MoqLiteMessages.kt b/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/moq/lite/MoqLiteMessages.kt index 59d8af06d..b55f2e0ee 100644 --- a/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/moq/lite/MoqLiteMessages.kt +++ b/nestsClient/src/commonMain/kotlin/com/vitorpamplona/nestsclient/moq/lite/MoqLiteMessages.kt @@ -21,22 +21,38 @@ package com.vitorpamplona.nestsclient.moq.lite /** - * moq-lite ALPN strings. The on-the-wire framing for Subscribe / Group - * / Announce did NOT change between Lite-03 and Lite-04, so advertising - * both via `wt-available-protocols` is safe — the relay picks whichever - * it prefers and our existing codec paths handle either. We keep 03 in - * the list as the previously-tested target until the production relay's - * Lite-04 path has interop coverage. + * moq-lite ALPN strings. ONLY [LITE_03] is wire-compatible with the + * codec in [MoqLiteCodec]; the other constants are kept for + * documentation and future codec upgrades. + * + * Subscribe / Group framing is identical across Lite-03 and Lite-04, + * but Lite-04 reshapes Announce.hops into an `OriginList` + * (`kixelated/moq` commit 45db108, "moq-lite/moq-relay: hop-based + * clustering"), adds an `exclude_hop` field to AnnounceInterest, and + * adds an `rtt` field to Probe. A relay that picks Lite-04 with our + * Lite-03 codec on the wire desyncs on the first Announce exchange. + * Don't add [LITE_04] to `wt-available-protocols` until + * [MoqLiteCodec] is version-aware and [MoqLiteAnnounce.hops] is a + * list rather than a single varint. * * `"moql"` is the legacy combined ALPN that requires an in-band SETUP * exchange — kept here for completeness; not advertised by the * factory. * - * Source: `kixelated/moq-rs/rs/moq-lite/src/version.rs:21-26`, - * `@moq/lite/connection/connect.js:277`. + * Source: `kixelated/moq/rs/moq-lite/src/lite/version.rs`, + * `kixelated/moq/rs/moq-lite/src/lite/announce.rs:11-105`, + * `kixelated/moq/rs/moq-lite/src/lite/probe.rs:9-55`. */ object MoqLiteAlpn { const val LITE_03: String = "moq-lite-03" + + /** + * `moq-lite-04` ALPN string. Wire-incompatible with [MoqLiteCodec] + * today — see the object kdoc for the codec diff. Defined here so + * a future patch that lands version-aware Announce / Probe codecs + * can drop it into the [QuicWebTransportFactory] sub-protocol list + * without re-deriving the constant. + */ const val LITE_04: String = "moq-lite-04" const val LEGACY: String = "moql" } diff --git a/nestsClient/src/jvmAndroid/kotlin/com/vitorpamplona/nestsclient/transport/QuicWebTransportFactory.kt b/nestsClient/src/jvmAndroid/kotlin/com/vitorpamplona/nestsclient/transport/QuicWebTransportFactory.kt index f305fc24c..4f5fe7e59 100644 --- a/nestsClient/src/jvmAndroid/kotlin/com/vitorpamplona/nestsclient/transport/QuicWebTransportFactory.kt +++ b/nestsClient/src/jvmAndroid/kotlin/com/vitorpamplona/nestsclient/transport/QuicWebTransportFactory.kt @@ -91,18 +91,26 @@ class QuicWebTransportFactory( * `connection closed err=invalid value` on the relay side and a stalled * subscribe / `subscribe stream FIN before reply` on the client side. * - * `moq-lite-04` is also advertised because the production relay - * (moq.nostrnests.com) and the kixelated browser client both ship - * Lite-04 now; without it in our list a Lite-04-only deployment - * would refuse the CONNECT. The on-the-wire framing for Subscribe / - * Group / Announce did NOT change between Lite-03 and Lite-04, so - * our existing codec handles either selection. List `moq-lite-03` - * first because it's our previously-tested negotiation target — - * a relay that supports both should pick the listed-first option, - * and a Lite-04-only relay falls through to the second entry. + * **Lite-04 is intentionally NOT advertised** even though the kixelated + * browser client now ships it. Lite-04 reshapes the on-the-wire + * Announce.hops field from a single varint count into a full + * `OriginList` (`kixelated/moq` commit 45db108, "moq-lite/moq-relay: + * hop-based clustering"), adds an `exclude_hop` field to + * AnnounceInterest, and adds an `rtt` field to Probe — Subscribe and + * Group framing are unchanged but Announce framing diverges. Our codec + * speaks pure Lite-03; if a Lite-04-preferring relay picks + * `moq-lite-04` from our advertised list, the very first Announce + * exchange would desync (we'd encode/read a bare hops varint where + * the peer expects `len + len × u62`) and the connection would abort. + * Until [com.vitorpamplona.nestsclient.moq.lite.MoqLiteCodec] gains + * version-aware Announce / AnnounceInterest / Probe paths and + * [com.vitorpamplona.nestsclient.moq.lite.MoqLiteAnnounce.hops] + * becomes a list, advertising Lite-04 is a footgun. See + * [com.vitorpamplona.nestsclient.moq.lite.MoqLiteAlpn] for the + * known-version constants. */ private val webTransportSubProtocols: List = - listOf(MoqLiteAlpn.LITE_03, MoqLiteAlpn.LITE_04), + listOf(MoqLiteAlpn.LITE_03), ) : WebTransportFactory { override suspend fun connect( authority: String,