propose

suspend fun propose(action: A): IndexedAction<A>

Proposes action for replication and suspends until a quorum commits it, drawing the next per-node monotonic serial as the dedup requestId.

Callable from any node: the leader appends directly; a follower or candidate forwards the proposal to the current leader and awaits commit there. Suspends cancellably if no leader is known yet.

Returns the IndexedAction carrying action, its assigned log index, and the stamped IndexedAction.dedupKey. The returned object re-wraps the caller's action directly rather than decoding the committed bytes — this avoids a redundant serialization round-trip since the action is already in hand.

Use the propose (action, requestId) overload instead when the caller is a durable client that needs cross-crash exactly-once (replay the same requestId on a post-crash retry).

Throws

if a forwarded proposal is rejected because the leader stepped down mid-flight. The caller may retry.


suspend fun propose(action: A, requestId: Long): IndexedAction<A>

Proposes action with a caller-pinned requestId (Raft §8 client serial) under the backing RaftNode's clientId, then suspends until a quorum commits it (same semantics as propose).

This is the exactly-once propose path for a durable client: replay the same requestId on a post-crash retry and the consumer's us.tractat.kuilt.raft.ClientSessionTable skips the serial it has already applied. The client supplies its stable identity at bootstrap (gameNode/gameHost/gameJoin/gameSpectate's identity parameter); requestId must be a per-client monotonic serial the caller owns — do not pass a log index or a random value.

Throws

if a forwarded proposal is rejected because the leader stepped down mid-flight. The caller may retry with the same requestId.