swactor-development-history/STREAMS_IMPLEMENTATION.md

339 lines
23 KiB
Markdown
Raw Normal View History

2026-02-23 05:07:59 +00:00
# Swactor Streams -- Implementation Status
## What Was Built
Stages 1-4 are implemented. Stages 1-3 built the stream primitive in `crates/streams/` (the `swactor-streams` crate). Stage 4 connected streams to the datastore so blob transfers use QUIC streams instead of sequential actor-message round-trips. All 42 tests pass (37 streams + 5 blob_transfer).
### Stage 1: Types, Wire Format, and Buffer Pool
Pure Rust -- no tokio, no iroh, no network. Compiles and tests in isolation.
#### `src/types.rs`
Core domain types for the stream system.
- **`StreamId([u8; 16])`** -- 16-byte random identifier. `Copy`, `Hash`, `Eq`, `Serialize`/`Deserialize`. Custom `Debug` (4-byte hex prefix) and `Display` (8-byte hex prefix) following the codebase's ID conventions. Not an `ActorAddress` -- streams are not actors and don't pollute the address space.
- **`StreamMode`** -- enum with `BlobTransfer` variant. Extensible for future modes (continuous streams, datagrams).
- **`StreamConfig`** -- negotiation parameters: `stripe_count` (default 4), `frame_size` (default 256KB), `metadata` (opaque bytes for application-level negotiation payloads like ContentHash).
- **`StreamError`** -- error enum covering `Closed`, `BrokenPipe`, `Disconnected`, `BufferExhausted`, `InvalidHeader`, and `ChunkVerificationFailed` (with expected/actual hashes for diagnostics).
- **`ResumeToken`** -- checkpoint for resuming interrupted transfers, carrying stream identity and progress counters.
#### `src/wire.rs`
Binary wire format for stream headers and data frames. Pure functions, no I/O.
- **Constants**: `MAGIC: [0x53, 0x57]` ("SW"), `VERSION: 0x01`, `ALPN: b"swactor/stream/1"`.
- **`StreamHeader`** -- the negotiation header sent at connection establishment. Wire layout: `[2B magic][1B version][16B stream_id][1B mode][1B stripe_count][4B frame_size][4B metadata_len][N metadata]`.
- **`encode_header` / `decode_header`** -- round-trippable serialization with validation (magic, version, mode, truncation checks).
- **Data frame format**: `[4B payload_len (big-endian)][payload]`. Deliberately minimal -- no per-frame type tags or checksums (QUIC provides TLS integrity). A zero-length payload signals end-of-stripe.
- **`encode_data_frame` / `decode_data_frame` / `encode_end_of_stripe`** -- frame-level codec.
#### `src/buffer.rs`
Pre-allocated buffer pool for zero-allocation data transfer.
- **`FrameBuf`** -- a `Box<[u8]>` with read/write cursors. `write(&[u8]) -> usize` fills from the write cursor, `read(&mut [u8]) -> usize` drains from the read cursor. `reset()` zeroes only the cursors (not the data) for fast recycling. `load(&[u8])` replaces content directly.
- **`BufferPool`** -- a fixed-size pool backed by `crossbeam::ArrayQueue<FrameBuf>` (lock-free MPMC). `checkout() -> Option<FrameBuf>` and `checkin(buf)` enable concurrent use between actor threads and tokio tasks without locks. `Clone` shares the underlying `Arc` so send/recv sides reference the same pool.
### Stage 2: StreamHandle, Channels, and Data Plane
Introduces tokio channels and async tasks but NOT iroh. Data-plane tasks are generic over `AsyncRead`/`AsyncWrite`, fully testable with `tokio::io::DuplexStream`.
#### `src/channel.rs`
Typed channel messages that move `FrameBuf`s by ownership (zero-copy handoff).
- **`SendCommand`** -- `Data(FrameBuf)`, `Flush`, `Close`. Actor -> send task.
- **`SendEvent`** -- `WriteReady`, `Error(StreamError)`, `Closed`. Send task -> actor.
- **`RecvCommand`** -- `Consumed(FrameBuf)`, `Close`. Actor -> recv task.
- **`RecvEvent`** -- `Data(FrameBuf)`, `Error(StreamError)`, `Closed`. Recv task -> actor.
#### `src/notify.rs`
Notification coalescing to prevent flooding actor mailboxes.
- **`NotifyFlag`** -- `AtomicU8` bitflags (`DATA_READY`, `WRITE_READY`, `CLOSED`, `ERROR`). `set(kind) -> bool` returns true only if the bit was previously clear, signaling a new notification should be injected. `clear(kind)` is called by the actor after handling.
- **`StreamEvent`** / **`StreamEventKind`** -- the lightweight sentinel message injected into actor mailboxes. Carries `stream_id` and `kind` (DataReady, WriteReady, Closed, Error).
- **`NotifySink`** -- held by data-plane tasks. Combines the shared `NotifyFlag` with an inject closure. Convenience methods: `data_ready()`, `write_ready()`, `closed()`, `error()`.
#### `src/handle.rs`
The actor-facing API for reading and writing stream data.
- **`SendHalf`** -- owns `mpsc::Sender<SendCommand>`, `mpsc::Receiver<SendEvent>`, a `BufferPool` clone, and an active `FrameBuf`. `try_write(&[u8]) -> Result<usize>` fills the active buffer and sends full buffers via `try_send` (non-blocking). Returns 0 on backpressure. `flush()` sends partial buffers. `close()` flushes remaining data and sends the Close command.
- **`RecvHalf`** -- owns `mpsc::Receiver<RecvEvent>`, `mpsc::Sender<RecvCommand>`, a `BufferPool` clone, and an active `FrameBuf`. `try_read(&mut [u8]) -> Result<usize>` drains the active buffer then pulls new buffers from the channel. Returns 0 when no data is available. `has_data()` peeks without consuming.
- **`StreamHandle`** -- combines `SendHalf` and `RecvHalf`. `Send` but not `Clone` (the mpsc receivers are not cloneable).
- **`create_stream_handle(stream_id, config, pool_size, channel_capacity)`** -- factory that returns `(StreamHandle, DataPlaneEndpoints)`. The handle goes to the actor; the endpoints go to the data-plane tasks.
#### `src/data_plane.rs`
Async tasks that bridge `StreamHandle` channels to actual byte streams.
- **`send_stripe_task<W: AsyncWrite>`** -- reads `SendCommand`s from the channel, wire-encodes them as data frames, writes to the transport, returns consumed buffers to the pool, and optionally notifies the actor via `NotifySink`.
- **`recv_stripe_task<R: AsyncRead>`** -- reads wire-encoded frames from the transport, loads payloads into `FrameBuf`s from the pool, sends `RecvEvent::Data` to the actor channel. Handles end-of-stripe sentinel and connection closure.
- **`spawn_send_stripes` / `spawn_recv_stripes`** -- spawn a set of stripe tasks from a writer/reader factory. The recv spawner merges all stripe outputs into a single `mpsc::Receiver<RecvEvent>`.
Generic over `AsyncRead + AsyncWrite + Send + Unpin + 'static`, so tests use `tokio::io::DuplexStream` with no network stack.
### Stage 3: QUIC Integration and StreamManager Actor
Connects the data-plane tasks to real QUIC streams via iroh. Introduces the `StreamManager` system actor with full open/accept/reject lifecycle. Modifies `IrohDriver` for generic ALPN routing and bootstraps the StreamManager in `swactor-node`.
#### `src/messages.rs`
Protocol types for the stream control plane.
- **`OneShot<T>`** -- Clone-friendly wrapper for non-Clone data (`StreamHandle`, `Connection`). Uses `Arc<Mutex<Option<T>>>` internally. First `.take()` extracts the value; subsequent calls (including from clones) return `None`. This allows non-Clone payloads inside Clone message enums required by the actor system's `Message` trait.
- **`StreamManagerMsg`** -- 8-variant enum for messages sent TO the StreamManager actor:
- `Open { target_node, mode, config, reply_to }` -- Request a new stream to a remote node.
- `Accept { stream_id, reply_to }` -- Accept an offered incoming stream.
- `Reject { stream_id }` -- Reject an offered incoming stream.
- `Listen { mode, listener }` -- Register as a stream listener for a given mode.
- `Close { stream_id }` -- Close a stream.
- `IncomingConnection { node_id, stream_id, mode, config, conn }` -- Internal: from accept bridge to StreamManager.
- `OpenCompleted { stream_id, reply_to, result }` -- Internal: async open task completed.
- `AcceptCompleted { stream_id, reply_to, result }` -- Internal: async accept task completed.
- **`StreamNotification`** -- 4-variant enum for notifications sent FROM StreamManager TO user actors:
- `StreamReady { stream_id, handle }` -- Stream is ready for use (open or accept completed).
- `StreamOffer { stream_id, mode, metadata, from_node }` -- A remote node is offering a stream.
- `StreamClosed { stream_id, reason }` -- A stream was closed.
- `StreamFailed { stream_id, error }` -- A stream open/accept failed.
#### `src/connection.rs`
Async connection cache for stream QUIC connections, separate from SWIM connections.
- **`StreamConnectionCache`** -- `HashMap<[u8; 32], Connection>` with health-check-on-access. `get_or_connect()` checks `conn.close_reason().is_none()` before reuse and falls back to connecting via `endpoint.connect(key, ALPN)`. `prune_closed()` for bulk cleanup. Uses the stream ALPN (`swactor/stream/1`).
#### `src/manager.rs`
The core StreamManager system actor.
- **`StreamManager`** -- implements `ActorInterface<Incoming = StreamManagerMsg>`. Manages active streams, pending incoming offers, listener registrations, and a connection cache. Holds an `Endpoint`, `tokio::runtime::Handle`, and `Arc<Runtime>` for spawning async tasks and sending messages back to itself.
- **`STREAM_MANAGER_NAME`** -- well-known name `"StreamManager"` for the name registry.
- **Open flow**: Generates `StreamId`, spawns a tokio task that connects, sends header on a control bi-stream, waits for a 1-byte accept/reject response, then creates `StreamHandle` + data-plane tasks, and sends `OpenCompleted` back to the StreamManager. StreamManager then delivers `StreamNotification::StreamReady` to the requesting actor.
- **Incoming flow**: Accept bridge reads header, sends `IncomingConnection` to StreamManager. StreamManager stores as pending, notifies matching listeners with `StreamOffer`.
- **Accept flow**: Takes pending connection, spawns tokio task that sends accept byte, creates `StreamHandle` + data-plane tasks, sends `AcceptCompleted` back. StreamManager delivers `StreamReady` to accepting actor.
- **Reject flow**: Sends reject byte on a uni-stream, drops the connection.
- **Close flow**: Removes stream state; data-plane tasks terminate when channels drop.
- **`handle_down`**: Cleans up streams owned by dead actors and removes dead listeners.
- **Data-plane spawning**: For each stream direction, a single tokio task opens N uni-streams and round-robins data frames across them. Recv tasks accept incoming uni-streams and dispatch each to a `recv_stripe_task`.
#### `src/accept.rs`
Bridge between incoming QUIC connections and the StreamManager actor.
- **`spawn_accept_bridge`** -- spawns a tokio task that reads from a channel of `(node_id, Connection)` pairs, accepting the control bi-stream, reading the stream header via `read_to_end` + `decode_header`, and forwarding `StreamManagerMsg::IncomingConnection` to the StreamManager via `runtime.send_to()`.
- **`handle_incoming`** -- public async function for per-connection header processing. Can also be called directly from the main loop (used by `swactor-node`).
#### Modified: `crates/distribution/src/iroh_driver.rs`
Generic ALPN support to route stream connections separately from SWIM.
- **`IrohDriverConfig`**: Added `additional_alpns: Vec<Vec<u8>>` field. All existing call sites updated with `additional_alpns: vec![]`.
- **Endpoint creation**: ALPNs now include both SWIM and any additional ALPNs (`vec![ALPN.to_vec()] + additional_alpns`).
- **Accept loop**: After accepting a connection, checks `conn.alpn()`. SWIM ALPN routes to `accepted_conns` (existing behavior). All other ALPNs route to `other_accepted_conns` (new buffer).
- **New field**: `other_accepted_conns: Arc<Mutex<Vec<(NodeId, Connection)>>>`.
- **New methods**: `endpoint() -> &Endpoint` (for outbound stream connections), `drain_other_connections() -> Vec<(NodeId, Connection)>` (polled from main loop).
#### Modified: `crates/streams/src/types.rs`
- Added `Hash` derive to `StreamMode` (needed as `HashMap` key in listeners registry).
#### Modified: `crates/streams/src/lib.rs`
- Added module declarations and re-exports for `accept`, `connection`, `manager`, `messages`.
- Re-exports: `StreamConnectionCache`, `StreamManager`, `STREAM_MANAGER_NAME`, `OneShot`, `StreamManagerMsg`, `StreamNotification`.
#### Modified: `crates/streams/Cargo.toml`
- Added `swactor-std` dependency (for `CtxMonitoring`, `RuntimeNaming`).
- Added `io-util` feature to `tokio` (for `AsyncWriteExt::flush`).
#### Modified: `crates/swactor-node/src/main.rs`
Bootstrap integration in `run_iroh()`.
- Passes `swactor_streams::ALPN.to_vec()` in `IrohDriverConfig::additional_alpns`.
- After driver creation, spawns `StreamManager::new(endpoint, tokio_handle, runtime)` as a named actor under `"StreamManager"`.
- In the main loop, drains `driver.drain_other_connections()` and spawns `handle_incoming` tasks for each, forwarding to the StreamManager.
#### Modified: `crates/swactor-node/Cargo.toml`
- Added `swactor-streams` dependency.
#### Modified: `crates/distribution/tests/common/iroh.rs`, `crates/dashboard/src/bin/swactor-node.rs`
- Updated all `IrohDriverConfig` construction sites with `additional_alpns: vec![]`.
### Stage 4: Datastore Stream Integration
Connects the stream system to the datastore so blob transfers flow over QUIC streams instead of sequential per-chunk actor-message round-trips. A 1GB blob with 1MB chunks that previously required 1,024 round-trips now flows in a single burst.
#### `crates/datastore/src/blob_transfer.rs` (NEW)
Async functions for sending/receiving blobs over StreamHandle. Runs inside tokio tasks, NOT actor handlers.
- **`BlobTransferError`** -- enum: `IncompleteTransfer(String)`, `ChunkVerificationFailed { expected, actual }`, `InvalidManifest(String)`, `Storage(String)`.
- **`ReceivedBlob`** -- `{ manifest: ObjectManifest, chunks: Vec<(ContentHash, Vec<u8>)> }`.
- **`send_blob(send, manifest, read_chunk)`** -- generic over an async callback `F: Fn(ContentHash) -> Future<Output = Result<Vec<u8>>>`. Writes `[4B manifest_json_len][manifest JSON]` preamble, then for each chunk in the manifest calls `read_chunk(hash)` and writes the raw bytes. Chunks are NOT preloaded -- the callback reads one at a time.
- **`recv_blob(recv)`** -- reads manifest preamble, deserializes JSON, then reads + blake3-verifies each chunk against the manifest's `ChunkRef` entries. Returns `ReceivedBlob`.
- **`poll_inbox(inbox, timeout)`** -- async version of `bridge.rs:poll_response`. Yields (`tokio::task::yield_now`) instead of `thread::sleep`, polling the swactor `Inbox` until a message arrives or timeout.
- **Internal helpers**: `write_all` (loops `try_write` + `yield_now`), `read_exact` (loops `try_read` + `yield_now`).
Wire format:
```
[4B manifest_json_length (u32 BE)]
[N bytes manifest JSON]
[chunk_0 raw bytes] <- size from manifest.chunks[0].size
[chunk_1 raw bytes]
...
```
#### `crates/datastore/src/actors/stream_listener.rs` (NEW)
Listens for incoming BlobTransfer stream offers and routes them to DatastoreNode.
- **`StreamListener`** -- `Incoming = StreamNotification`. State: `datastore_node: ActorAddress`, `stream_manager: Option<ActorAddress>`.
- `on_start`: looks up `"StreamManager"` via `ctx.where_is()`, sends `StreamManagerMsg::Listen { mode: BlobTransfer }`.
- `handle(StreamOffer)`: extracts 32-byte ContentHash from `metadata`, sends `DatastoreNodeMsg::HandleStreamOffer` to DatastoreNode. Rejects if metadata != 32 bytes.
#### `crates/datastore/src/actors/stream_downloader.rs` (NEW)
Opens a stream to a remote node and downloads a blob.
- **`StreamDownloader`** -- `Incoming = StreamNotification`. Constructor takes: `content_hash`, `source_node`, `datastore_node`, `blob_store`, `reply_to`, `stream_manager`, `tokio_handle`, `runtime`.
- `on_start`: sends `StreamManagerMsg::Open { target_node, mode: BlobTransfer, config.metadata: content_hash.0.to_vec() }`.
- `handle(StreamReady)`: takes handle via `OneShot::take()`, spawns tokio task:
- Calls `recv_blob(&mut recv_half)`.
- Writes each chunk to BlobStore via `runtime.send_to(blob_store, WriteChunk)` (fire-and-forget).
- Writes manifest via `runtime.send_to(blob_store, WriteManifest)` (fire-and-forget).
- Sends `DatastoreNodeMsg::StreamDownloadComplete` to DatastoreNode.
- On error: sends `DatastoreNodeMsg::StreamDownloadFailed`.
- Actor calls `ctx.stop_self()` after spawning the task.
- `handle(StreamFailed)`: sends `StreamDownloadFailed`, stops self.
#### `crates/datastore/src/actors/stream_server.rs` (NEW)
Serves a blob to a requesting node over a stream, reading chunks on-demand.
- **`StreamServer`** -- `Incoming = StreamNotification`. Constructor takes: `stream_id`, `content_hash`, `blob_store`, `stream_manager`, `tokio_handle`, `runtime`.
- `on_start`: sends `StreamManagerMsg::Accept { stream_id }`.
- `handle(StreamReady)`: takes handle, spawns tokio task:
- Reads manifest from BlobStore via `runtime.new_inbox()` + `poll_inbox` (async Inbox polling).
- Calls `send_blob(&mut send_half, &manifest, |chunk_hash| { ... })` with a callback that reads each chunk on-demand from BlobStore via a fresh Inbox.
- At most one chunk is in memory at a time. Chunks flow directly from BlobStore to stream.
- Actor calls `ctx.stop_self()`.
- `handle(StreamFailed)`: stops self.
#### Modified: `crates/datastore/src/messages.rs`
Added 5 new variants to `DatastoreNodeMsg`:
- `DownloadViaStream { content_hash, source_node, reply_to }` -- triggers a stream download.
- `HandleStreamOffer { stream_id, content_hash, from_node, stream_manager }` -- routes incoming stream offers.
- `StreamDownloadComplete { content_hash, manifest, reply_to }` -- download succeeded; persist metadata.
- `StreamDownloadFailed { content_hash, reason, reply_to }` -- download failed; notify caller.
- `ConfigureStreams { stream_manager, tokio_handle, runtime }` -- late-binding stream support.
Changed from `#[derive(Debug, Clone)]` to `#[derive(Clone)]` with manual `Debug` impl (because `Arc<Runtime>` doesn't implement `Debug`).
#### Modified: `crates/datastore/src/actors/datastore_node.rs`
Added stream support fields and handlers to the coordinator actor.
- **New fields**: `runtime: Option<Arc<Runtime>>`, `tokio_handle: Option<tokio::runtime::Handle>`, `stream_manager: Option<ActorAddress>` -- all initialized to `None`.
- **`handle_configure_streams`**: stores runtime/tokio_handle/stream_manager.
- **`handle_download_via_stream`**: spawns `StreamDownloader`. Returns `TransferFailed` if streams not configured.
- **`handle_stream_offer`**: spawns `StreamServer`.
- **`handle_stream_download_complete`**: creates `ObjectEntry`, sends `MetadataMsg::PutObject` to metadata actor with the original `reply_to` for direct response routing.
- **`handle_stream_download_failed`**: sends `DatastoreResponse::TransferFailed` to `reply_to`.
#### Modified: `crates/datastore/src/actors/mod.rs`
Added module declarations for `stream_downloader`, `stream_listener`, `stream_server`.
#### Modified: `crates/datastore/src/lib.rs`
Added `pub mod blob_transfer`.
#### Modified: `crates/datastore/src/bridge.rs`
- Added `datastore_addr: ActorAddress` field to `DatastoreGroup` (stored during `spawn()`).
- Added `configure_streams(&self, stream_manager, tokio_handle)` method: sends `ConfigureStreams` to DatastoreNode, spawns and registers `StreamListener` under `"StreamListener"`.
#### Modified: `crates/datastore/Cargo.toml`
- Added `swactor-streams = { path = "../streams" }` and `tokio = { version = "1", features = ["sync", "rt", "time"] }` dependencies.
- Added dev-dependencies for testing: `swactor-streams`, `tokio` with `rt-multi-thread`, `macros`, `io-util`.
#### Modified: `crates/swactor-node/src/main.rs`
After StreamManager registration, wires stream support into the datastore:
```rust
if let Some(group) = ds_group {
group.configure_streams(stream_mgr_addr, driver.tokio_handle());
}
```
## Test Coverage
42 tests across all modules:
| Category | Tests | What they verify |
|----------|-------|------------------|
| `types` | 4 | StreamId uniqueness, Debug/Display formatting, StreamConfig defaults |
| `wire` | 8 | Header round-trip (basic + property-based), bad magic/version/truncation rejection, data frame round-trip (basic + property-based), end-of-stripe sentinel |
| `buffer` | 7 | FrameBuf write/read/reset/load, BufferPool checkout/checkin/exhaustion/recycling/sharing |
| `notify` | 4 | Set returns true first time / false on duplicate, clear re-enables, independent flags, read shows all bits |
| `data_plane` | 9 | Single-stripe end-to-end transfer, multi-chunk ordered delivery (20 chunks), 4-stripe round-robin (100 chunks), graceful close, notification coalescing, backpressure detection |
| `messages` | 5 | OneShot take-once semantics, clone sharing, debug format, StreamManagerMsg is Message, StreamNotification is Message |
| `blob_transfer` | 5 | Small blob round-trip (single chunk), multi-chunk round-trip (4MB / 256KB chunks / 16 chunks), corrupted chunk detection (blake3 verification), truncated stream detection, property-based arbitrary blob round-trips |
Property-based tests (via `proptest`) cover:
- Arbitrary stream headers (random IDs, stripe counts 1-16, frame sizes 1KB-1MB, metadata 0-256 bytes)
- Arbitrary data frame payloads (0-256KB)
- Arbitrary blob transfers (random data 1-64KB, chunk sizes 256B-8KB)
## Dependency Footprint
### `swactor-streams` crate
- `swactor` (core actor types, with `serde` feature)
- `swactor-std` (for `CtxMonitoring`, `RuntimeNaming`)
- `shared-types` (ContentHash)
- `distribution` (NodeId, iroh re-exports)
- `crossbeam-queue` (lock-free buffer pool -- already a workspace dep)
- `tokio` (mpsc channels, async I/O traits, io-util)
- `iroh` (QUIC transport, connections, endpoints)
- `blake3`, `serde`, `getrandom`
Dev dependencies: `proptest`, `tokio` (with rt-multi-thread, macros, test-util, io-util).
### `swactor-datastore` crate (Stage 4 additions)
- `swactor-streams` (stream primitives, messages, types)
- `tokio` (sync, rt, time -- for spawning async blob transfer tasks and `poll_inbox`)
Dev dependencies: `swactor-streams`, `tokio` (with rt-multi-thread, macros, io-util).
## Next Steps
### Remaining MVP Work
These items complete the minimum viable stream-based blob transfer:
1. **Two-node integration test** -- full open/accept/data-transfer/close cycle with real iroh endpoints and two `DatastoreGroup` instances. Verifies StreamListener receives offers, StreamServer serves blobs, StreamDownloader receives and persists them. This is the critical end-to-end validation that all the pieces work together over real QUIC.
2. **CtxStreams extension trait** (`crates/streams/src/ctx_ext.rs`) -- convenience methods on `Ctx`: `stream_open()`, `stream_listen()`, `stream_accept()`, `stream_reject()`, `stream_close()`. Looks up `"StreamManager"` via `where_is()` and wraps the message construction. Reduces boilerplate for any actor wanting to use streams.
3. **Resume tokens** -- checkpoint emission every N chunks or N bytes during `send_blob`/`recv_blob`. Stored in `ResumeToken` (already defined in `types.rs`). On reconnect, receiver sends its token in `StreamConfig.metadata` and sender seeks to the right chunk offset.
### Post-MVP Phases
- **Dashboard stream metrics** -- expose active streams, bytes transferred, and transfer rates through the existing dashboard infrastructure.
- **Continuous Streams** -- `ContinuousStream` mode for unbounded data (ML gradient streams, data pipelines). Single bidirectional QUIC stream, variable-sized frames, ring buffer backpressure.
- **Unreliable Datagrams** -- QUIC datagram-based mode for latency-sensitive data (voice/video, game state). Sequence-based dropping, jitter buffer.
- **Priority and QoS** -- per-stream priority, write scheduling across concurrent streams, QUIC stream priority hints.
- **Parallel Unordered Transfer** -- independent per-chunk QUIC streams for workloads where any chunk is consumable independently (distributed ML gradient exchange).