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

Link copied to clipboard

The implausible-term bound's malformed arm: the frame's term is negative.

Link copied to clipboard

The implausible-term bound's jump arm (#1833, made relative by #1897): the frame's term is more than RaftConfig.maxTermJump above ours.

Link copied to clipboard

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.

Link copied to clipboard

onTimeoutNow guard 1: the frame's term is below ours — a §3.10 transfer from a leader we have already moved past.

Link copied to clipboard

onTimeoutNow guard 2: this node is already a RaftRole.Leader or a RaftRole.Candidate.

Link copied to clipboard

onTimeoutNow guard 3 (#1889): the frame's term is strictly above ours, so it carries no authority this node can check.

Link copied to clipboard

onTimeoutNow guard 4 (#1900, landed in #1938): the sender is not the node leaderForTerm holds as this term's established leader.

Link copied to clipboard

onTimeoutNow guard 5: this node is a RaftRole.Learner. A learner never votes and must never start an election.

Link copied to clipboard

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.

Link copied to clipboard

RaftEngine.batchRefusal bound 2 (#1832): an AppendEntries batch that is not contiguous from its own probe point — some entries[i].index != prevLogIndex + 1 + i.

Link copied to clipboard

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.

Link copied to clipboard

RaftEngine.snapshotChunkRefusal bound 1 (#1868): an InstallSnapshot whose lastIncludedIndex is outside 0..MAX_PLAUSIBLE_INDEX.

Link copied to clipboard

RaftEngine.snapshotChunkRefusal bound 2 (#1868): an InstallSnapshot whose lastIncludedTerm is outside 0..min(term, MAX_PLAUSIBLE_TERM).

Link copied to clipboard

RaftEngine.committedTermFloorRefusal (#1910): an InstallSnapshot advancing our commit frontier whose lastIncludedTerm is below the term of our own entry at commitIndex.

Link copied to clipboard

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

Link copied to clipboard

Returns a representation of an immutable list of all enum entries, in the order they're declared.

Link copied to clipboard
expect val name: String
Link copied to clipboard
expect val ordinal: Int
Link copied to clipboard

The RaftMetric.WedgeSuspected.Gate a refusal at this gate is reported under, or null when this gate feeds no wedge diagnosis at all.

Functions

Link copied to clipboard

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.)

Link copied to clipboard

Returns an array containing the constants of this enum type, in the order they're declared.