aff2ee182b
Variant (B) from the three-way fix menu in the multiplexing-interop investigation: keep `:quic` strict about per-stream backpressure (the audit-4 #3 "INTERNAL_ERROR: stream … consumer overflowed" tear-down stays the contract for app-data overflow on bidi streams) but expose an explicit, opt-in helper for peer-initiated UNI streams that the application has decided it does not need to interpret. Root cause confirmed in QuicConnectionParser.kt:290: when the server opens its three RFC 9114 §6.2.1 peer-uni streams (CONTROL + QPACK_ENCODER + QPACK_DECODER) and the H3 client does not consume them, the parser routes their bytes into each stream's bounded incomingChannel (capacity 64). Once the QPACK encoder issues dynamic-table inserts beyond 64 chunks the next chunk overflows trySend, sets QuicStream.overflowed, and the parser maps that to markClosedExternally — the entire connection dies. Notes on scope: - The `Http3GetClient` and `:quic-interop` runner mentioned in the investigation prompt do NOT exist on the `main` worktree this branch starts from. The fix here is therefore `:quic`-only: the public `awaitIncomingPeerStream` API was already sufficient for an integrator to write the accept loop themselves; this commit wraps the common case in `drainPeerInitiatedUniStreamsIntoBlackHole` and updates the doc on `awaitIncomingPeerStream` so the next integrator landing the H3 GET client doesn't hit the same trap. - Variant (C) — silent default drain in `:quic` itself — was deliberately rejected: defaults that swallow application bytes are the misconfiguration we want type-system-or-API-explicit. The new helper requires the caller to pass a CoroutineScope, so opt-in is unmistakable in any callsite. Regression test coverage in PeerUniStreamDrainTest: - pre_fix_no_consumer_overflows_and_tears_down_connection — pushes 65 chunks (capacity + 1) on a SERVER_UNI stream with no consumer; asserts the connection transitions to CLOSED. Pins the existing backpressure contract. - drainPeerInitiatedUniStreamsIntoBlackHole_keeps_connection_alive — same setup but with the new helper running on a side scope; pushes 256 chunks (4× capacity) and asserts the connection stays CONNECTED. With the helper sabotaged, this test fails at line 119 with status=CLOSED, confirming it actually exercises the fix. Full quic test suite: 295 tests, 0 failures, 0 errors. https://claude.ai/code/session_01HcvfQq1ttPV9PkRoJb4nyT