Motivation
A busy terminal, TCP stream, or telemetry channel cannot crowd out other traffic on the same connection. #488 proposes TCP channels with their own flow control, but imo we can introduced a shared mechanism rather than maintain a second set of window and credit rules.
Proposed direction
- Negotiate receive windows and delivery limits in
subscribe, in both directions. The response confirms the accepted settings and the host’s receive limits. These belong to each subscription, not shared channel state.
- Allow logical messages to span multiple small JSON-RPC messages. Carry fragments as strings, not another layer of base64; do not split surrogate pairs. Count UTF-16 bytes and account for JSON escaping when enforcing frame limits. Reassemble before normal typed decoding or reducer application.
- Treat the window as a target: starting a message needs available credit, but an already-started message may finish beyond the window. This avoids requiring callers to predict encoded size or repeatedly resize payloads. Keep hard frame/message limits and bounded buffers so this allowance cannot grow without limit.
- Return credit when the bounded consumer releases the message, not merely when JSON arrives. For TCP, that means releasing bytes from the downstream stream buffer. Use the same cumulative credit mechanism for all channel types.
- Schedule fragments fairly across subscriptions and bound the underlying transport queue. Fragmentation and windows alone do not prevent one busy channel from monopolizing delivery. Small, bounded credit/reset/liveness controls must not depend on data credit.
- Include initial snapshots and reconnect replay in bounded delivery, rather than allowing large RPC results to bypass it. Use per-channel recovery cursors so one stalled channel does not prevent other channels from progressing safely.
Effect on TCP
I would keep TCP byte offsets, duplicate suppression, EOF/close/reset, and same-socket replay. Those describe stream correctness. I would move window negotiation and consumed-credit updates out of TCP-specific state/actions into the shared subscription machinery. Arbitrary TCP bytes would still need their existing encoding on a JSON transport.
This is a design proposal, not a requirement to block #488. The main questions are the precise credit-release contract, bounded completion beyond the window, and how bootstrap/recovery delivery fits the existing APIs. Subscription flow control also needs to be clear about its scope: other large RPC results need separate bounds or chunking to provide connection-wide protection.
Motivation
A busy terminal, TCP stream, or telemetry channel cannot crowd out other traffic on the same connection. #488 proposes TCP channels with their own flow control, but imo we can introduced a shared mechanism rather than maintain a second set of window and credit rules.
Proposed direction
subscribe, in both directions. The response confirms the accepted settings and the host’s receive limits. These belong to each subscription, not shared channel state.Effect on TCP
I would keep TCP byte offsets, duplicate suppression, EOF/close/reset, and same-socket replay. Those describe stream correctness. I would move window negotiation and consumed-credit updates out of TCP-specific state/actions into the shared subscription machinery. Arbitrary TCP bytes would still need their existing encoding on a JSON transport.
This is a design proposal, not a requirement to block #488. The main questions are the precise credit-release contract, bounded completion beyond the window, and how bootstrap/recovery delivery fits the existing APIs. Subscription flow control also needs to be clear about its scope: other large RPC results need separate bounds or chunking to provide connection-wide protection.