ClusterClient
A Raft learner-client that proposes commands through the cluster leader and exposes the committed log stream for state-machine application.
Obtain an instance via clusterClientWithNode (tests / caller-managed transport) or via the CoroutineScope.clusterClient extension (production relay-room usage, available in S3b once the Seam-reconnect transport adapter is wired).
Exactly-once proposals
propose (no-arg overload) delegates to RaftNode.propose which auto-mints and persists a monotonic requestId internally — a retry after failover with the same id coalesces to the original committed entry via us.tractat.kuilt.raft.ClientSessionTable.shouldApply.
propose with an explicit requestId is the public cross-crash exactly-once overload: callers that persist a requestId and replay it after a crash get at-most-once application of the command.
Failover model (S3a API contract; S3b wires the production path)
On transport tear the underlying ServerClusterReconnect advances to the next endpoint. When it presents the previous us.tractat.kuilt.session.partition.ResumeToken to the new server, the response is a terminal us.tractat.kuilt.session.partition.ResumeResult.Refused (proven by #532; the code is RejectCode.ResumeTokenInvalid, since each server mints its own RoomId and keeps its reconnect windows in memory), so a cross-server resume always degrades to fresh-join. ClusterClient treats that refusal as a fall-back-to-fresh-join signal, not an error.
See also
for the test / caller-managed-transport construction path.