Merge main into claude/cross-stack-interop-test-XAbYB

Picks up:
  - 32e578d Merge #2754 — fix jvm-test timeout (commons NestViewModel disposal)
  - c7b0dc5 Merge #2753 — fix green-circle UI
  - d3abf12 Merge #2752 — fix amethyst connection-loss
  - d854d75 Merge #2751 — stream-priority follow-up

Resolved any nestsClient build-script overlap manually.
This commit is contained in:
Claude
2026-05-06 22:39:42 +00:00
13 changed files with 796 additions and 358 deletions
@@ -1037,6 +1037,13 @@ class MoqLiteSession internal constructor(
// 150 ms late still falls inside hang's default ~200 ms
// jitter buffer) and avoids the dropout entirely.
val uni = transport.openUniStream()
// Mirror moq-rs `Publisher::serve_group`
// (`rs/moq-lite/src/lite/publisher.rs`): newer groups get higher
// priority so the QUIC writer drains fresh audio first when
// retransmits queue up under loss. Saturating cast guards a
// theoretical broadcast that runs long enough for `sequence` to
// exceed Int.MAX_VALUE (≈ 71 years at 1 group/sec); defensive only.
uni.setPriority(sequence.coerceAtMost(Int.MAX_VALUE.toLong()).toInt())
uni.write(Varint.encode(MoqLiteDataType.Group.code))
uni.write(MoqLiteCodec.encodeGroupHeader(MoqLiteGroupHeader(subscribeId, sequence)))
return uni
@@ -162,6 +162,8 @@ class FakeBidiStream internal constructor(
override suspend fun finish() {
write.close()
}
override fun setPriority(priority: Int) = Unit
}
class FakeReadStream internal constructor(
@@ -186,4 +188,6 @@ private class ChannelWriteStream(
override suspend fun finish() {
channel.close()
}
override fun setPriority(priority: Int) = Unit
}
@@ -112,6 +112,22 @@ interface WebTransportWriteStream {
/** Half-close the write side (FIN). No further writes after this call. */
suspend fun finish()
/**
* Hint to the transport about this stream's drain priority relative
* to other streams on the same session. Higher value drains first
* under congestion; same-priority streams keep round-robin order.
* Default 0 = unchanged round-robin behaviour.
*
* moq-lite uses this to bias the writer toward newer group streams
* (sequence-numbered, fresher audio) so a backlog of retransmits on
* an older group doesn't starve the listener of fresh frames. See
* `Publisher::serve_group` in `rs/moq-lite/src/lite/publisher.rs`.
*
* Implementations that don't model priority (e.g. the in-memory
* fake) MAY treat this as a no-op.
*/
fun setPriority(priority: Int)
}
/**
@@ -365,6 +365,10 @@ private class QuicBidiStreamAdapter(
stream.send.finish()
driver.wakeup()
}
override fun setPriority(priority: Int) {
stream.priority = priority
}
}
private class QuicReadStreamAdapter(
@@ -392,6 +396,10 @@ private class QuicUniWriteStreamAdapter(
stream.send.finish()
driver.wakeup()
}
override fun setPriority(priority: Int) {
stream.priority = priority
}
}
/** Adapter for a WT peer-initiated uni stream whose prefix has been stripped. */
@@ -431,4 +439,14 @@ private class StrippedWtBidiStreamAdapter(
?: error("peer-initiated bidi stream has no finish — demux didn't wire one")
finish()
}
/**
* No-op: peer-initiated bidi streams arrive through the demux as a
* [com.vitorpamplona.quic.webtransport.StrippedWtStream] which exposes
* only `send`/`finish` closures, not the underlying [QuicStream]. The
* moq-lite priority use case targets locally-opened uni group streams
* only, so this path doesn't need to model priority — see the
* [WebTransportWriteStream.setPriority] contract.
*/
override fun setPriority(priority: Int) = Unit
}