RefusalGate
Which guard refused an inbound frame — the gate of RaftTraceEvent.FrameRefused.
Every guard named here refuses by returning, so without this its only observable is the absence of a state change. An absence carries no attribution: as soon as two guards refuse the same frame, a test asserting "term unchanged, still a Follower" cannot say which one did it, and the upstream guard's coverage silently drops to zero. That is measured, not hypothetical — a mutation survey (#1980) found four of RaftEngine.onTimeoutNow's five guards deletable with the whole module green, and found that adding one state-effect test per guard reproduces the defect rather than fixing it, because each new test is shadowed exactly as the old ones were. This enum is the attribution those tests had no way to make (#1989).
Closed on purpose
wedgeGate is an exhaustive when with no else, so a value added here cannot compile without deciding whether the wedge metric hears about it — the mechanism RaftMessage.wireTerm and RaftMessage.isLeaderToPeer already use to keep a new frame type from slipping silently past a gate (#1973). What no compiler can force is adding the value in the first place; the FrameRefusedTest suite's reachability test is the other half, and it fails on an entry no emit site produces.
What no type can close, and the slice that is closed anyway
The guard above runs in one direction only, and the next reader must not assume otherwise. FrameRefusedTest.everyRefusalGateIsReachable proves declared→emitted: every value below has a live emit site. The converse — emitted→declared, that every refusal of an inbound frame names a gate — is not compile-time enforceable in general (#2033). "This return refuses a frame" is a property of control flow, not of a type; Kotlin has no effect system, so nothing stops a new if (…) return in a handler body from dropping a frame silently, and no test that inspects only declared values can see it. Funnelling every refusal through RaftEngine.refuseFrame does not change that either — a funnel catches only what someone chooses to route into it.
What is enforced is the slice where the whole gap actually lived. Every factored validator on the inbound path returns RefusalGate? — null admits, non-null names the gate that refused — (RaftEngine.batchRefusal, snapshotChunkRefusal, committedTermFloorRefusal, adoptLeaderForTerm), so a refusing clause added to one of them cannot compile without naming a gate: return false has stopped being expressible there. Keep it that way — when a handler grows a new frame refusal, factor it into a validator of that shape rather than writing a bare return in the handler body.
Two alternatives were weighed and rejected. A sealed Disposition return on the eleven handlers converts a silent skip into a lying Processed — visible in a diff, still unenforced, and a large blast radius for that. A lexical detekt/Gradle scanner in the shape of forbidRunCatchingCancellableUnderNonCancellable would key on the debug { } log text rather than on control flow, so rewording a message evades it: a smell detector, not a proof.
Order
Grouped by where the engine evaluates them, and in evaluation order within each group. The two implausible-term arms and the §5.2/§8 leader-authority gate run at the dispatch boundary in RaftEngine.onMessage, before any handler. The five TimeoutNow* guards run inside RaftEngine.onTimeoutNow. The AppendEntries* and InstallSnapshot* guards run inside their own handlers, ahead of every side-effect those handlers have. ForgedLeaderForTerm is last because it is shared: both of those two handlers reach it, and both reach it after their own frame-shape bounds.
Entries
The implausible-term bound's malformed arm: the frame's term is negative.
The implausible-term bound's jump arm (#1833, made relative by #1897): the frame's term is more than RaftConfig.maxTermJump above ours.
The §5.2/§8 leader-authority gate (#1383, #1889): the frame is a leader→peer RPC (AppendEntries / InstallSnapshot / TimeoutNow) whose true sender is not in this node's committed voter set.
onTimeoutNow guard 1: the frame's term is below ours — a §3.10 transfer from a leader we have already moved past.
onTimeoutNow guard 2: this node is already a RaftRole.Leader or a RaftRole.Candidate.
onTimeoutNow guard 3 (#1889): the frame's term is strictly above ours, so it carries no authority this node can check.
onTimeoutNow guard 4 (#1900, landed in #1938): the sender is not the node leaderForTerm holds as this term's established leader.
onTimeoutNow guard 5: this node is a RaftRole.Learner. A learner never votes and must never start an election.
RaftEngine.batchRefusal bound 1 (#1832): an AppendEntries whose prevLogIndex is outside 0 .. Long.MAX_VALUE - entries.size - 1 — a probe point below the log origin, or one so high that computing the batch's expected indices would overflow.
RaftEngine.batchRefusal bound 2 (#1832): an AppendEntries batch that is not contiguous from its own probe point — some entries[i].index != prevLogIndex + 1 + i.
RaftEngine.batchRefusal bound 3 (#1832): an AppendEntries carrying an entry whose term is outside 0..term — a term no honest leader could have stamped, since no entry may carry a term above the leader's own.
RaftEngine.snapshotChunkRefusal bound 1 (#1868): an InstallSnapshot whose lastIncludedIndex is outside 0..MAX_PLAUSIBLE_INDEX.
RaftEngine.snapshotChunkRefusal bound 2 (#1868): an InstallSnapshot whose lastIncludedTerm is outside 0..min(term, MAX_PLAUSIBLE_TERM).
RaftEngine.committedTermFloorRefusal (#1910): an InstallSnapshot advancing our commit frontier whose lastIncludedTerm is below the term of our own entry at commitIndex.
RaftEngine.adoptLeaderForTerm (#1906): a same-term AppendEntries or InstallSnapshot from a peer that is not the node already established as this term's leader.
Properties
Returns a representation of an immutable list of all enum entries, in the order they're declared.
The RaftMetric.WedgeSuspected.Gate a refusal at this gate is reported under, or null when this gate feeds no wedge diagnosis at all.
Functions
Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
Returns an array containing the constants of this enum type, in the order they're declared.