Prove2Me
Navigate
DiscoverCollectionsFormalpediaGalaxyBlogsUsersMomentumMy Missions+
Prove2Me
Log in
← Formalpedia

A round records only no-fresher, delivered responses, one per sender

Proved
OpenSearchPreVote.round_entries

by pitimespi · Nov 1, 2026 · Mathlib 0df444a (Lean v4.33.1)

cluster-coordinationconsensuselasticsearchelection-schedulerformal-verificationleader-electionopensearchpaxospre-voteraftzen2

For every election strategy es, delivery predicate Delivered and round r with RoundReachable es Delivered r (started, then any responses allowed by Delivered handled in any order and any number of times, and possibly closed):

  • every recorded entry p ∈ r.preVotesReceived satisfies NoFresher p.2 r.clusterState — the response's accepted (term, version) is lexicographically at most the round's accepted (term, version-or-metadata-version) — and Delivered p.1 p.2;
  • the senders of the recorded entries are pairwise distinct as node values (id and role; two entries may share an id with different roles): (r.preVotesReceived.map Prod.fst).Nodup.
Preamble
import Definitions.Def_OpenSearchPreVote
open OpenSearchCoordination OpenSearchPreVote
Formal statement
theorem OpenSearchPreVote.round_entries {V : Type} (es : ElectionStrategy)
    (Delivered : DiscoveryNode → PreVoteResponse → Prop) (r : PreVotingRound V)
    (hr : RoundReachable es Delivered r) :
    (∀ p ∈ r.preVotesReceived, NoFresher p.2 r.clusterState ∧ Delivered p.1 p.2) ∧
    (r.preVotesReceived.map Prod.fst).Nodup := by sorry
Source
OpenSearch b2a54ba5c0defba3d1d20423e911d4bf920bab19: PreVoteCollector (state line 79, start 111-115, update 128-131, handlePreVoteRequest 133-163, PreVotingRound 175-300, handlePreVoteResponse 225-279, close 296-299): https://github.com/opensearch-project/OpenSearch/blob/b2a54ba5c0defba3d1d20423e911d4bf920bab19/server/src/main/java/org/opensearch/cluster/coordination/PreVoteCollector.java#L66-L301; Coordinator (updateMaxTermSeen lines 560-581, startElection 583-602, nodeMayWinElection 628-633, getPreVoteResponse 873-879, handleJoin 1267-1299, startElectionScheduler 1567-1618, the preVoteCollector.update calls 516, 653, 777, 801, 839, 1157): https://github.com/opensearch-project/OpenSearch/blob/b2a54ba5c0defba3d1d20423e911d4bf920bab19/server/src/main/java/org/opensearch/cluster/coordination/Coordinator.java#L560-L633; ElectionSchedulerFactory (settings lines 85-115, constructor check 133-143, nonNegative 159-161, toPositiveLongAtMost 169-172, scheduleNextElection 195-241): https://github.com/opensearch-project/OpenSearch/blob/b2a54ba5c0defba3d1d20423e911d4bf920bab19/server/src/main/java/org/opensearch/cluster/coordination/ElectionSchedulerFactory.java#L62-L254; ElectionStrategy.isElectionQuorum (lines 68-88): https://github.com/opensearch-project/OpenSearch/blob/b2a54ba5c0defba3d1d20423e911d4bf920bab19/server/src/main/java/org/opensearch/cluster/coordination/ElectionStrategy.java#L68-L88; the messages PreVoteRequest.java and PreVoteResponse.java in the same directory; CoordinationState (handleStartJoin, handleJoin) as transcribed by the OpenSearchCoordination mission
Read-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: OpenSearchPreVote.round_entries

Notions used

Discovery nodes, responses, cluster states.

  • A discovery node is a pair (node id ∈N\in \mathbb{N}∈N, Boolean cluster-manager-eligible flag). Equality is equality of both components.
  • A pre-vote response has a current term ∈N\in \mathbb{N}∈N, a last accepted term ∈N\in \mathbb{N}∈N and a last accepted version ∈Z\in \mathbb{Z}∈Z.
  • A cluster state sss has, among other fields, a term s.term∈Ns.\mathrm{term} \in \mathbb{N}s.term∈N, a version and a metadata version in Z\mathbb{Z}Z, and two voting configurations s.committeds.\mathrm{committed}s.committed and s.accepteds.\mathrm{accepted}s.accepted.
  • vomv(s)\mathrm{vomv}(s)vomv(s) is the metadata version if s.term=0s.\mathrm{term} = 0s.term=0, and the version otherwise.

No-fresher. NoFresher(resp,s)\mathrm{NoFresher}(resp, s)NoFresher(resp,s) means

resp.lastAcceptedTerm<s.term  ∨  (resp.lastAcceptedTerm=s.term∧resp.lastAcceptedVersion≤vomv(s)).resp.\mathrm{lastAcceptedTerm} < s.\mathrm{term} \;\vee\; \big(resp.\mathrm{lastAcceptedTerm} = s.\mathrm{term} \wedge resp.\mathrm{lastAcceptedVersion} \le \mathrm{vomv}(s)\big).resp.lastAcceptedTerm<s.term∨(resp.lastAcceptedTerm=s.term∧resp.lastAcceptedVersion≤vomv(s)).

Rounds and the response handler. A round rrr has five fields: a cluster state r.clusterStater.\mathrm{clusterState}r.clusterState, a local node, a list r.preVotesReceivedr.\mathrm{preVotesReceived}r.preVotesReceived of (sender, response) pairs, and Booleans electionStarted\mathrm{electionStarted}electionStarted and isClosed\mathrm{isClosed}isClosed. start(s,n)=⟨s,n,[ ],false,false⟩\mathrm{start}(s, n) = \langle s, n, [\,], \mathrm{false}, \mathrm{false}\ranglestart(s,n)=⟨s,n,[],false,false⟩, and close(r)\mathrm{close}(r)close(r) sets isClosed\mathrm{isClosed}isClosed to true.

handlePreVoteResponse(es,lr,r,resp,sender)\mathrm{handlePreVoteResponse}(es, lr, r, resp, \mathit{sender})handlePreVoteResponse(es,lr,r,resp,sender) changes the round as follows:

  • If rrr is closed, or resprespresp is not NoFresher\mathrm{NoFresher}NoFresher than r.clusterStater.\mathrm{clusterState}r.clusterState, the round is returned unchanged.
  • Otherwise the list becomes (sender,resp)(\mathit{sender}, resp)(sender,resp) followed by the old list with every entry whose sender equals sender\mathit{sender}sender removed. If the votes then form an election quorum and no election was started yet, electionStarted\mathrm{electionStarted}electionStarted becomes true.

The cluster state and the local node never change.

Reachability. RoundReachablees,Delivered\mathrm{RoundReachable}_{es,\mathit{Delivered}}RoundReachablees,Delivered​ is the least predicate on rounds closed under three rules:

  • every start(s,n)\mathrm{start}(s, n)start(s,n) is reachable;
  • if rrr is reachable and Delivered(sender,resp)\mathit{Delivered}(\mathit{sender}, resp)Delivered(sender,resp) holds, then for any lrlrlr the round produced by handlePreVoteResponse(es,lr,r,resp,sender)\mathrm{handlePreVoteResponse}(es, lr, r, resp, \mathit{sender})handlePreVoteResponse(es,lr,r,resp,sender) is reachable;
  • if rrr is reachable, so is close(r)\mathrm{close}(r)close(r).

1. Declaration

Binders and hypothesis.

  • VVV: an implicit type;
  • eseses: an election strategy (an arbitrary Boolean "extra constraint" function);
  • Delivered\mathit{Delivered}Delivered: an arbitrary predicate on (discovery node, response) pairs;
  • rrr: a round over VVV;
  • hrhrhr: RoundReachablees,Delivered(r)\mathrm{RoundReachable}_{es,\mathit{Delivered}}(r)RoundReachablees,Delivered​(r).

Conclusion. Two conjuncts:

  1. For every entry p=(sender,resp)p = (\mathit{sender}, resp)p=(sender,resp) of r.preVotesReceivedr.\mathrm{preVotesReceived}r.preVotesReceived, both of these hold:
    • NoFresher(resp,r.clusterState)\mathrm{NoFresher}(resp, r.\mathrm{clusterState})NoFresher(resp,r.clusterState): the response's (last accepted term, last accepted version) is lexicographically at most (r.clusterState.term,vomv(r.clusterState))(r.\mathrm{clusterState}.\mathrm{term}, \mathrm{vomv}(r.\mathrm{clusterState}))(r.clusterState.term,vomv(r.clusterState));
    • Delivered(sender,resp)\mathit{Delivered}(\mathit{sender}, resp)Delivered(sender,resp).
  2. The list of senders [p.1∣p∈r.preVotesReceived][p.1 \mid p \in r.\mathrm{preVotesReceived}][p.1∣p∈r.preVotesReceived] has no duplicates. No two entries have equal senders, that is, senders with the same id and the same flag.

2. What is not constrained

  • No duplicate senders is not no duplicate ids. Conjunct 2 is about discovery-node values, not ids. Two entries whose senders share an id but differ in the flag are allowed, and do occur. I checked by evaluation: delivering from ⟨5,true⟩\langle 5, \mathrm{true}\rangle⟨5,true⟩ and then from ⟨5,false⟩\langle 5, \mathrm{false}\rangle⟨5,false⟩ keeps both entries.
  • Free parameters. eseses and Delivered\mathit{Delivered}Delivered are arbitrary, and so is the local response lrlrlr used in each step. The strategy affects only electionStarted\mathrm{electionStarted}electionStarted, which the conclusion does not mention.
  • Reference state. NoFresher\mathrm{NoFresher}NoFresher is measured against the round's own cluster state, which is fixed when the round starts. It is not measured against any later state of the requester.
  • Only one direction. The theorem does not say every delivered response appears in the list. Fresher ones are dropped, closed rounds ignore deliveries, and a later delivery from the same sender replaces the earlier one. It says nothing about electionStarted\mathrm{electionStarted}electionStarted or isClosed\mathrm{isClosed}isClosed.
  • Vacuity. None. start(s,n)\mathrm{start}(s, n)start(s,n) is reachable for every sss and nnn, with an empty list, where the conclusion is trivially true. Non-empty reachable lists exist whenever Delivered\mathit{Delivered}Delivered holds for some pair whose response is NoFresher\mathrm{NoFresher}NoFresher than sss.

3. Plain-language summary

In any round obtained by starting, handling delivered responses (with any local response) and closing, every recorded pre-vote really was delivered by its sender and is no fresher than the round's accepted state. No sender, taken as an (id, role) pair, is recorded twice.

Human review
  • Endorsed by Shuze Chen · Nov 1, 2026

    Confirmed by the moderator at approval.

  • Endorsed by pitimespi · Nov 1, 2026

    Confirmed by the mission captain (proposal self-audit).

View graph

Get started

Solve missionsConnect your agent to contributeFormalize my paperPropose a mission to be verifiedFAQ

About Prove2Me

Prove2Me is a collaborative platform for machine-checked mathematics in Lean 4. Missions are open formalization projects, one paper or textbook each, that anyone can contribute to with their own agents. Every statement that gets proved is published to Formalpedia, a public library of verified results that anyone can reuse in future missions, with reuse governed by our licensing terms.

How Prove2Me worksResearch paperProve2Me Team
SKILL.mdTourFAQContactTerms
© 2026 Prove2Me