docs(arch): resolve OQ-45 — no application-level windowing; QUIC per-stream flow control suffices

The backpressure chain is complete by construction: QUIC flow control
→ bounded drainer channel → bounded stdout channel → OS pipe/PTY buffer
→ process write() blocks. Every link awaits its producer; no unbounded
buffer breaks the chain. The reversal path (an additive ControlMessage
variant, not a wire-format header change) is noted in ADR-052's
consequences as a two-way door, not the expected path.

Tightened ADR-052 assumption 1 from a hedge ('expected to work; a POC
would confirm') to a decided constraint. Updated all OQ-45 references
across the tty spec docs from 'open (low risk)' to 'resolved'.
This commit is contained in:
glm-5.2 committed 2026-07-07 09:36:18 +00:00
1 parent df5d04af1d
commit db4da1e6f0
7 files changed
+131 -59

No files matched your search

@@ -3,20 +3,62 @@
- **Origin**: `docs/research/alknet-tty/phase-0-findings.md` OQ-TTY-03;
[crates/tty/tty-wire.md](crates/tty/tty-wire.md) (no windowing in the
chunk format).
- **Status**: open (low risk)
- **Status**: resolved
- **Door type**: Two-way
- **Priority**: low
- **Resolution**: The chunk format has no windowing — QUIC's per-stream
flow control handles backpressure. This is expected to suffice for
high-throughput stdout (e.g., `cargo build` output): the docker POC's
logs subscription handled multi-line output without issue, and QUIC's
bidi-stream flow control is the established backpressure mechanism. A
POC with real high-volume output (a deliberately large `cargo build`
or `find /` over a high-bandwidth connection) would confirm. If a
flow-control problem surfaces, the reversal is a per-stream
flow-control window in the chunk format (a two-way-door extension to
the wire format, additive — a new control message type for window
updates, not a header change). Not blocking; the default assumption is
QUIC flow control suffices.
- **Resolution**: No application-level windowing. QUIC's per-stream flow
control is the backpressure mechanism — the chunk format carries no
window. This is decided, not a default assumption.
The backpressure chain is complete by construction — every link awaits
its producer, so slowness at the client's read end propagates all the
way back to the child process's stdout write without any unbounded
buffering link:
1. **Client reads slowly → QUIC flow control.** The server's
`write_chunk` writes into a quinn `SendStream`, which respects
per-stream flow control. When the client's receive window fills,
the send awaits. (Standard, mature quinn behavior — not something
alknet-tty inventes.)
2. **Send awaits → drainer channel backpressures.** The drainer task
writes chunks to the client one at a time. When `write_chunk`
awaits, the drainer stops pulling from the bounded `writer_rx`
channel (depth 64 in the POC's `session.rs`).
3. **Drainer channel fills → stdout pump backpressures.** The
stdout→client pump does `writer_tx.send(chunk).await`; when the
drainer isn't pulling, the send awaits.
4. **Stdout pump awaits → backend stdout channel backpressures.** The
pump stops receiving from the backend's stdout channel (the local
backend's `mpsc::Receiver<Bytes>`, also bounded at 64).
5. **Stdout channel fills → reader thread backpressures.** The
backend's reader thread (`portable_pty` master reader, or a piped
`Child::stdout`) does `blocking_send`; when the channel is full,
the std thread blocks and stops reading from the kernel.
6. **Reader thread stops → OS pipe/PTY buffer fills → process blocks.**
The kernel PTY buffer (or `Stdio::piped()` buffer, typically 64 KiB)
fills, and the child process's `write()` to stdout blocks. The
process is throttled.
Every link in the chain awaits its producer. The chain is the standard
composition of QUIC flow control + bounded tokio channels + OS pipe
buffers — the same pattern the docker POC's logs subscription and the
tty POC's PTY pump already use. A high-throughput stdout workload
(e.g., `cargo build` output) throttles at the process when the client
can't keep up; no unbounded buffer breaks the chain.
The two-way-door reversal — a per-stream window-update control message
on stream_type 3 — is an additive extension to the control channel
(a new `ControlMessage` variant), not a wire-format header change. It
is not the expected path; it is noted in ADR-052's consequences as the
cheap reversal if a flow-control problem ever surfaces that QUIC's
defaults cannot handle (e.g., a pathological stream that needs
sub-QUIC-window backpressure signaling). Tuning concerns (read buffer
size, channel depth) are implementation-level, not architectural, and
don't warrant an ADR.
- **Cross-references**: ADR-052, [tty-wire.md](crates/tty/tty-wire.md),
[tty-adapter.md](crates/tty/tty-adapter.md)
[tty-adapter.md](crates/tty/tty-adapter.md),
`/workspace/alknet-tty-poc/src/session.rs` (the three-pump driver —
the bounded channels at every link),
`/workspace/alknet-tty-poc/src/local_pty.rs` (the blocking→async
bridge — the reader thread that backpressures into the kernel).