Stable Conduit
A StableConduit wraps a link and provides automatic reconnection with replay of missed items. It implements the Conduit interface: the session layer above it sees a reliable, ordered stream of items, even when the underlying link fails and is replaced.
StableConduit is entered only after the transport prologue has accepted the
stable conduit mode. The stable-conduit handshake specified on this page is
therefore not the first exchange on a fresh link attachment.
StableConduit continuity is below the RPC retry layer. It preserves conduit items; it does not by itself define when an RPC should be retried, resumed, or replayed as the same logical operation. See Retry.
A StableConduit is constructed with a LinkSource — an async provider of fresh links. When the current link fails, the StableConduit obtains a new link from the source and attempts to resume conduit continuity.
Handshake
Every stable-conduit attachment begins with a stable handshake after the
transport prologue has accepted stable. The client sends a ClientHello,
the server responds with a ServerHello. These messages are postcard-encoded
and sent as raw link payloads (not wrapped in stable frames).
ClientHello carries:
resume_key—Option<ResumeKey>.Nonefor a fresh session;Some(key)to resume a previous session.last_received—Option<PacketSeq>. The highest sequence number the client has successfully received.Noneif no items have been received yet.
ServerHello carries:
resume_key— a freshly generatedResumeKeyfor this session. The client MUST use this key in subsequent reconnection attempts.last_received—Option<PacketSeq>. The highest sequence number the server has successfully received.Noneif no items have been received yet.
A resume key is an opaque byte buffer generated by the server. It MUST be at least 16 bytes and SHOULD be generated using a cryptographically secure random source. The server uses it to identify which session a reconnecting client belongs to.
Framing
After the handshake, all traffic is wrapped in frames. Each frame carries:
seq— aPacketSeq(u32) assigned by the senderack— an optionalPacketAckpiggybacked by the senderitem— the conduit-level item (e.g. a sessionMessage)
On the wire, a frame is encoded as a postcard-serialized FrameHeader
(seq + ack) concatenated with the separately postcard-serialized item
bytes. The replay buffer stores the complete encoded frame bytes
(header + item). On replay, frames are retransmitted with their
original sequence numbers preserved.
Sequencing
Each direction has an independent sequence counter. Sequence numbers start at 0 and increment by 1 for each frame sent, wrapping at u32 boundaries.
Within a single link, sequence numbers MUST be strictly increasing (modulo u32 wrap). A receiver that observes a sequence number less than or equal to its last received sequence (accounting for wrap) MUST ignore the duplicate frame.
Acknowledgment
Acknowledgments are piggybacked on data frames. A frame's ack field,
when present, contains a PacketAck with a max_delivered field: the
highest sequence number the sender of the ack has successfully received
and processed.
Upon receiving an ack, the sender MUST trim its replay buffer: all
frames with sequence numbers less than or equal to max_delivered
can be discarded, as the peer has confirmed receipt.
Replay buffer
The sender MUST retain the encoded frame bytes (header + item) in a replay buffer until the peer acknowledges receipt via an ack. On reconnection, unacknowledged frames are retransmitted with their original sequence numbers.
Replayed items MUST be sent in their original sequence order before any new items are sent on the fresh link.
Reconnection
When a link fails, the StableConduit obtains a new link from its
LinkSource and performs a new handshake. The client sends a ClientHello
with the resume_key from the previous ServerHello and its
last_received sequence number.
Upon receiving a ClientHello with a valid resume_key, the server
identifies the session, determines which items the client missed (those
with sequence numbers greater than last_received), and replays them
on the new link before sending any new items.
Similarly, the client uses the server's last_received from the
ServerHello to replay any items the server missed.
If the server does not recognize the resume_key (e.g. the session
expired or the server restarted), it MUST reject the resume attempt.
The client MUST treat this as a session loss and surface an error to
the layers above.
What happens after that session loss is governed by Retry: stable reconnection stops at conduit continuity, while session continuity, operation-level retry, and caller-visible failure outcomes are defined separately there.