Votes keep counting during a stable election: once in the election term, the candidate accepts every voter's join for that term whenever it arrives
ProvedOpenSearchProgress.election_vote_acceptedFor every payload type V, cluster parameters P with P.InitCompatible and P.strategy = ElectionStrategy.DEFAULT_INSTANCE, every cluster W with Reachable P W, every node c, term t and list of node ids Q such that
cand every member ofQare cluster-manager-eligible:P.eligible c = trueandP.eligible q = truefor everyq ∈ Q;cand every member ofQare in a term belowt:(W.node q).currentTerm < tforq = cand for everyq ∈ Q;- every member of
Qhas an accepted state no fresher thanc's, compared ashandleJoincompares a join with the node's state:(W.node q).lastAcceptedTerm < (W.node c).lastAcceptedTerm, or the two terms are equal and(W.node q).lastAcceptedVersionOrMetadataVersion ≤ (W.node c).lastAcceptedVersionOrMetadataVersion; chas a nonempty last accepted configuration (as after a bootstrap or after accepting a publication):(W.node c).lastAcceptedConfiguration.isEmpty = false;
and every cluster W' with ElectionExec P c t Q (W.node c).lastAcceptedTerm (W.node c).lastAcceptedVersion W W' (a stable election period for c, t and Q starting at W) in which c is in term t, (W'.node c).currentTerm = t: for every join j with W'.sent (.join j), j.sourceNode.id ∈ Q, j.targetNode.id = c and j.term = t, there are a state cs' and a flag b with (W'.node c).handleJoin P.strategy j = .ok (cs', b) and j.sourceNode.id ∈ cs'.joinVotes.nodes.
Whatever has happened since the period started (deliveries in any order, duplicates, the steps the period allows the other nodes, commits at c and at the voters), once c is in term t each voter's join for t is accepted by c whenever it is delivered, and the vote is counted. A join delivered while c is still below t is not covered, and is rejected (the terms differ): in the model a voter may handle c's start-join request for t before c does.
import Definitions.Def_OpenSearchProgress open OpenSearchCoordination OpenSearchSafety OpenSearchProgress
theorem OpenSearchProgress.election_vote_accepted {V : Type} (P : Params) (hP : P.InitCompatible)
(hes : P.strategy = ElectionStrategy.DEFAULT_INSTANCE) (W : Cluster V) (hW : Reachable P W)
(c : NodeId) (t : Nat) (Q : List NodeId) (hc : P.eligible c = true) (hQ : ∀ q ∈ Q, P.eligible q = true)
(hterm : ∀ q, q = c ∨ q ∈ Q → (W.node q).currentTerm < t)
(hfresh : ∀ q ∈ Q, (W.node q).lastAcceptedTerm < (W.node c).lastAcceptedTerm ∨
((W.node q).lastAcceptedTerm = (W.node c).lastAcceptedTerm ∧
(W.node q).lastAcceptedVersionOrMetadataVersion ≤ (W.node c).lastAcceptedVersionOrMetadataVersion))
(hconf : (W.node c).lastAcceptedConfiguration.isEmpty = false)
(W' : Cluster V)
(hE : ElectionExec P c t Q (W.node c).lastAcceptedTerm (W.node c).lastAcceptedVersion W W')
(hct : (W'.node c).currentTerm = t) (j : Join) (hj : W'.sent (.join j)) (hsrc : j.sourceNode.id ∈ Q)
(htgt : j.targetNode.id = c) (hjt : j.term = t) :
∃ cs' b, (W'.node c).handleJoin P.strategy j = .ok (cs', b) ∧ j.sourceNode.id ∈ cs'.joinVotes.nodes := by sorryRead-back
What the Lean code literally says, in plain math · claude-opus-5-5 (independent sub-agent, blind: Lean code + auditor instructions only)
Read-back: OpenSearchProgress.election_vote_accepted
Notions used
The full expansions are in readback_Def_OpenSearchProgress.md. This section repeats what the statement needs.
Node-state notation. For a node state :
- is the current term (a natural number) and the last accepted cluster state;
- and are that state's term and (integer) version;
- is its metadata version if its term is 0, and its version otherwise;
- and are its last committed and last accepted voting configurations;
- is the list of ids in the join votes, is
startedJoinSinceLastReboot, iselectionWonand islastPublishedVersion.
means .
Clusters and reachability. A cluster assigns a node state to every node id, and has a set of messages that only ever grows. means is obtained from an initial cluster by finitely many Steps. In an initial cluster every node is with a term-0 state with empty configurations, and no message has been sent. A Step is one successful handler call at one node, with its output sent; the kinds are bootstrap, start-join, join, client value, publish, respond, commit, restart of an eligible node (term kept), and restartAny of a non-eligible node (any term, any state).
The election period. is a finite, possibly empty, sequence of election steps from to . Each election step is a Step of one of the following kinds, where is the acting node's state:
- bootstrap of a node ;
- start-join at any node , on a request from an eligible in term with :
- it succeeds iff ;
- then moves to term , with , , votes cleared and ;
- sends the join ;
- join: any node handles any sent join whose target id is that node;
- publish: any node handles any sent publication request , provided that whenever or . The response goes to ;
- respond: any node handles any sent publish response addressed to it, and a resulting commit is sent;
- commit: any node handles any sent commit;
- restart of an eligible node ;
restartAnyof a non-eligible node.
There is no client-value step, so no new publication request is sent during the period. In this theorem, and .
handleJoin(es, σ, j) succeeds iff all of the following hold, checked in this order:
- ;
- ;
- ;
- not ( and );
- is non-empty.
On success it returns . The new join-vote list is : is prepended if and the id is not yet present, and the list is unchanged otherwise. 's is recomputed, and its may be reset. The strategy influences only and , not success and not the vote list.
1. Declaration
The universally quantified variables and hypotheses, in order:
| Name | Type / statement |
|---|---|
V (implicit) | Type: the payload type |
P | Params |
hP | : for bootstrap configurations and lists of eligible ids, |
hes | (no additional quorum constraint) |
W | Cluster V: the cluster at the start of the period |
hW | |
c | node id: the candidate |
t | : the election term |
Q | list of node ids: the voters |
hc | |
hQ | |
hterm | |
hfresh | |
hconf | is non-empty (isEmpty = false) |
W' | Cluster V |
hE | |
hct | |
j | Join |
hj | |
hsrc | |
htgt | |
hjt |
Conclusion.
Unfolded. Write . The conclusion says that all five guards of handleJoin pass at for , and that the source's id is in the resulting vote list. Guard 1 () follows directly from hjt and hct. The remaining content is:
- (ii) ;
- (iii) ;
- (iv) ;
- (v) is non-empty;
- (vi) , or already.
is then determined as the handler's output, and records whether the vote was new. Nothing is claimed about , or .
In words: at the end of any stable election period in which has reached term , every term- join that a voter has addressed to can be handled by without rejection, and handling it records that voter's vote.
2. What is not constrained
-
.
- It is not required to be a quorum of anything; this theorem has no quorum hypothesis.
- It may contain .
hfreshis then trivial for , and may be 's own join to itself. - It may contain duplicates, or nodes outside 's configurations.
- If ,
hsrccannot hold and the statement is vacuous. That is the only degenerate case.
-
Other nodes. Nodes outside are unconstrained at : any term (even ), any accepted state, possibly elected in some term. The period allows them every step except start-joins to terms other than 's request for , and new publications.
-
The join . Only its source id, target id and term are constrained. Its and , and its source node's cluster-manager flag, are not hypotheses. So claims (iii), (iv) and (vi) assert facts about whichever term- joins from voters to can exist in . The target node's flag is not constrained either, only its id.
The following is derived by me, not stated. In a reachable cluster, the joins a voter has produced by have terms its current term . So was produced during the period, by the voter handling 's request for ; in the period, term can only be entered on 's request. Its source node is , which is flagged cluster-manager because is eligible.
-
Whether was already handled. may already have handled during the period. The claim is that handling it (again) at succeeds and leaves the vote present. The statement is about the pure handler applied to , not about a step. Since the period does not restrict join steps, and is sent with target id , the handler's success is exactly what an election join step from needs.
-
Freshness.
hfreshcompares voters with using , exactlyhandleJoin's measure, but only at . The period's freshness bound uses (version) instead. The two coincide for when . When , the period lets and the voters accept no publication at all (no term-0 publication exists in a reachable cluster), so the voters' metadata versions cannot move. The theorem thus implicitly claims that the start-of-period comparison survives every stable period, including voters' acceptances of publications whose key is . -
's configurations. Only
hconf( non-empty at ) is assumed. Nothing is assumed about , and nothing links 's configurations to . Claim (v) is about . -
hes,hP. These are global assumptions on . The conclusion's form does not depend on the strategy, which affects only and ; neither is mentioned. -
Empty execution.
htermwithhctforces and rules out the empty execution: , so at least 's start-join into occurs, on a request whose requester is . -
Vacuity. The hypotheses are jointly satisfiable. Example:
- eligible nodes 1 and 2;
- .
InitCompatibleholds, because every quorum of contains both nodes; - the default strategy;
- both nodes bootstrapped, from an initial cluster, with the same term-0 state: version 0, metadata version 0, configurations ;
- , , .
In the period, node 1 start-joins on its own request for term 1, and node 2 start-joins on node 1's request for term 1, sending . Every hypothesis holds at , and the conclusion is a real claim.
3. Plain-language summary
Start from any reachable cluster in which:
- the candidate and the voters are eligible and in terms below ;
- has a non-empty accepted configuration;
- no voter's last accepted state is fresher than 's, in
handleJoin's comparison.
Then run any stable election period: no start-join anywhere to a term except on 's request for , no new publications, no restarts or bootstraps of or of voters, and and the voters accept nothing fresher than 's starting state. If has reached term , then can accept any term- join that a voter has sent it, and accepting it records the voter's vote. The theorem does not claim that a voter's join is ever sent, nor that wins.
Confirmed by the mission captain (proposal self-audit).
Confirmed by the moderator at approval.