UnsettledJointConfig

RaftEngine.onChangeMembership guard 6: the effective config is still Joint — a §6 transition has not settled onto a Simple.

Declared, and with no known reachable trajectory. membershipState always reflects the last config entry, so on a leader membershipState is Joint means the last config entry is a Joint, and then either it is uncommitted — in which case UncommittedConfigEntry refuses first, being evaluated above this — or it is committed, in which case a Simple(C_new) has already been appended above it in the same call that committed it (onConfigCommitted's Joint branch, or finalizeInheritedCommittedJoint on election, which also covers the Joint-compacted-into-the- snapshot case where the log holds no config entry at all). Either way this guard sees a Simple. A leader never truncates its own log, and onInstallSnapshot demotes to Follower before it touches membership, so nothing turns a leader's settled Simple back into a Joint.

It is kept rather than deleted: it is also what makes the current.config read below it total, and the argument above is a derivation over five call sites, which is exactly the kind of thing that stops holding quietly. What it is not is coverage — no test claims this value, and one that reached it through a hand-built engine state would be proving its own fixture.

The load-bearing premise is demoteToFollowerOnLeaderContact firing unconditionally, which is what puts every other recomputeMembership() site on a Follower. Make that demotion conditional, add a fifth call site, or let a leader adopt a config without appending an entry, and this guard goes live again — silently, since nothing asserts the premise or the guard. Whether to delete it, keep it as documented depth, or hunt the missed trajectory stays open under #2737.

Properties

Link copied to clipboard

A short phrase naming the condition, used to build the default exception message.

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