FrameRefused

data class FrameRefused(val clock: Long, val node: NodeId, val from: NodeId, val messageType: RaftMessageType, val gate: RefusalGate) : RaftTraceEvent

A frame from a peer was refused by gate — the one variant that reports something the engine did not do.

Every dispatch-boundary guard refuses by returning, so a refusal's only other observable is the absence of a state change, and absences carry no attribution: when two guards refuse the same frame, "term unchanged, still a Follower" cannot say which one did it (#1980, #1989). This event names the guard. One frame in, one event out — no run threshold, no latch, no commit-index precondition.

Not a wedge detector

RaftMetric.WedgeSuspected keeps that job, and a production consumer that wants to know whether a node is jammed must watch it, not this. Two observables, two jobs: the metric is the sustained-condition diagnosis, this is the per-frame attribution.

The reason for the split is that this event is losable by design. trace is a MutableSharedFlow with BufferOverflow.DROP_OLDEST, so emitting it can never backpressure consensus — which is exactly what makes it safe to emit on a path a remote frame controls, and exactly why WedgeSuspected needs a run threshold and a latch and this does not. The consequence, stated here rather than left to be rediscovered as a bug: a hostile flood of refused frames evicts honest trace events from the buffer. A slow consumer sees the same thing. Neither harms the engine; both mean this flow is evidence, not a ledger.

Constructors

Link copied to clipboard
constructor(clock: Long, node: NodeId, from: NodeId, messageType: RaftMessageType, gate: RefusalGate)

Properties

Link copied to clipboard
open override val clock: Long

Logical monotonic clock — incremented on every emitted event.

Link copied to clipboard

the frame's true origin, already unwrapped from any relay envelope.

Link copied to clipboard

the guard that refused it.

Link copied to clipboard

the refused frame's wire type. A typed value rather than m::class.simpleName, which is not guaranteed identical across Kotlin/Native, JVM and wasmJs and so cannot be asserted on cross-target.

Link copied to clipboard

this engine's own id — the recipient that refused the frame.