mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
The transport binding was the last piece missing from agent text streams, and it did not need a new QUIC implementation — `:quic` already had the whole hard part. What it needed was entering that stack at the right layer. `nestsClient` speaks WebTransport: HTTP/3, Extended CONNECT, QPACK, SETTINGS. Its `WebTransportSession` abstraction begins above all of that. Marmot's binding is raw QUIC — it negotiates its own ALPN (`marmot.quic_broker.v1` / `marmot.quic_stream.v1`) and writes frames straight onto QUIC streams, with no HTTP/3 anywhere in it. So this reuses everything below that line — connection, TLS 1.3, ALPN negotiation, stream multiplexing, loss recovery, the UDP socket — and none of the WebTransport wrapper. The codecs are in quartz next to the rest of agent-text-stream, because they are pure bytes and that is where the conformance risk lives: the control envelope with its literal 21-byte protocol string and its trailing-byte rejection, the uint32 frame codec with both the broker's blind cap and a policy-aware one, `quic://` candidate parsing down to ignoring everything after the authority and never sending an IP literal as SNI, and the first record's stream id pinning the rest. `:marmotQuic` is the connection layer, mirroring how `:nestsClient` sits on `:quic`. A publisher claims a room on a uni stream, a subscriber reads the fan-out on a bidi one, and an endpoint that does not take our ALPN is reported as unusable so the caller moves to the next candidate rather than waiting on records that never come. Verified against MDK's own `marmot-quic-broker`, which is the only way to know a wire format is right: our publisher and subscriber meet inside the reference broker, the records come back, open under the group-derived key and fold to the publisher's transcript hash, and the broker keeps rooms apart. Opt in with -DmarmotQuicBroker=host:port; the cases skip visibly without one, so an ordinary test run needs no broker. Still not wired at the app layer: nothing yet mints a kind-1200 start, picks a candidate, or renders a live preview, so `send` (0xF2D2) and `fanout` (0xF2D4) stay unadvertised. The direct path has no start-payload candidate format in v1 and is unimplemented. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016kCuA6tc4JQzHPCDd39GHq