mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 00:37:41 +00:00
Production trace pinned the audio-cliff to the exact moment our
writer emits its first MAX_STREAMS_UNI extension (frame 0x13).
With the default cap of 100 and the half-window threshold check at
count=50, the listener emits MAX_STREAMS_UNI(150) at count=50, then:
16:47:18.092 MAX_STREAMS_UNI emit oldCap=100 → newCap=150
16:47:18.210 transport delivered uni stream #50 ← LAST stream
16:47:20.204 udpRecvDatagrams=431
16:47:25.209 udpRecvDatagrams=443 (+12)
16:47:30.213 udpRecvDatagrams=443 ← FROZEN forever
`udpRecvDatagrams` (kernel-level UDP receive counter) freezes:
the relay's UDP packets stop reaching the OS. Our QUIC state still
believes the connection is alive (sendCredit=2^62-1, pendingBytes=0,
peerInitMaxStreamsUni=10000) but `peerInitiatedUniCount` is stuck at
51 forever. The relay, meanwhile, FINs both inbound SUBSCRIBE bidis
on the publisher side at +10s, telling the publisher "this listener
went away" — split-brain.
The cliff is repeatable but not at a fixed stream count: prior runs
saw cliffs at 124 (where the *second* bump at count=100 would have
fired) and 61 (where some intermediate condition tripped). The
common thread is the rolling-extension path, not the absolute count.
Without a packet capture from the relay we can't pin whether our
MAX_STREAMS_UNI frame is malformed, mis-sequenced, ill-timed against
moq-rs's flow-control state machine, or something subtler. But moq-rs
itself advertises `max_concurrent_uni_streams = 10000` for exactly
the audio-rooms workload — every Opus group is a fresh peer-initiated
uni stream — and matching that takes the listener to ~5 000 groups
(at framesPerGroup=5, Opus 20ms, that's ~8 minutes of audio) before
the half-window threshold trips at all. For any realistic Nest
duration we never need to extend.
The extension code path stays in QuicConnectionWriter.kt:395 — it's
correct per RFC 9000 §19.11, the bug is in moq-rs (or its Quinn
config) and we're working around it for now.
Side effect: we also bump the bidi cap implicitly — but that's
controlled by initialMaxStreamsBidi (still 100), unaffected by this
change. Bidi streams are control-stream-only in moq-lite (Subscribe
+ Announce), well below 100.
https://claude.ai/code/session_01PYYez8a6sjiakyjAxsfCEQ