Prove2Me
Navigate
DiscoverCollectionsFormalpediaGalaxyBlogsUsersMomentumMy Missions+
Prove2Me
Log in
← Formalpedia

Acknowledgements keep counting during a stable publication

Proved
OpenSearchProgress.publication_acks_accepted

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

cluster-coordinationconsensuselasticsearchformal-verificationleader-electionlivenessmessage-passingopensearchpartial-synchronypaxosprogresspublicationraftzen2

For 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 Q of cluster-manager-eligible node ids, such that c has won the election and is in term t ((W.node c).electionWon = true, (W.node c).currentTerm = t), every cluster state s, term pt and version pv such that c has sent the publication of s with ghost parent (pt, pv) (W.sent (.publishRequest c s pt pv)), s.term = t and s.version = (W.node c).lastPublishedVersion (it is c's latest publication), and every cluster W' with PublicationExec P c t Q W W':

  1. every q ∈ Q with (W'.node q).currentTerm = t has already acknowledged (t, s.version) to c (W'.sent (.publishResponse q c ⟨t, s.version⟩)) or accepts s now: (W'.node q).handlePublishRequest ⟨s⟩ = .ok (cs', r) for some cs' and r;
  2. for every q ∈ Q with W'.sent (.publishResponse q c ⟨t, s.version⟩), c accepts that acknowledgement and counts it: (W'.node c).handlePublishResponse (P.dn q) ⟨t, s.version⟩ = .ok (cs', o) for some cs' and o with q ∈ cs'.publishVotes.nodes.

Item 1 covers only the nodes of Q that are in term t at W'. The period allows a node of Q below term t to reach it by handling a start-join from c for t, as Coordinator.ensureTermAtLeast does when a node receives a publication of a higher term, after which item 1 applies to it; the witness of publication_possible uses this step, but this theorem does not state that it is enabled. A node of Q above term t stays above it, so item 1 never applies to it.

Preamble
import Definitions.Def_OpenSearchProgress
open OpenSearchCoordination OpenSearchSafety OpenSearchProgress
Formal statement
theorem OpenSearchProgress.publication_acks_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) (hQ : ∀ q ∈ Q, P.eligible q = true)
    (hwon : (W.node c).electionWon = true) (hct : (W.node c).currentTerm = t)
    (s : ClusterState V) (pt : Nat) (pv : Int) (hs : W.sent (.publishRequest c s pt pv)) (hst : s.term = t)
    (hsv : s.version = (W.node c).lastPublishedVersion)
    (W' : Cluster V) (hE : PublicationExec P c t Q W W') :
    (∀ q ∈ Q, (W'.node q).currentTerm = t →
      W'.sent (.publishResponse q c ⟨t, s.version⟩) ∨
      ∃ cs' r, (W'.node q).handlePublishRequest ⟨s⟩ = .ok (cs', r)) ∧
    (∀ q ∈ Q, W'.sent (.publishResponse q c ⟨t, s.version⟩) →
      ∃ cs' o, (W'.node c).handlePublishResponse (P.dn q) ⟨t, s.version⟩ = .ok (cs', o) ∧
        q ∈ cs'.publishVotes.nodes) := by sorry
Source
OpenSearch b2a54ba5c0defba3d1d20423e911d4bf920bab19: Coordinator (handlePublishRequest lines 454-526 with ensureTermAtLeast at 512, startElection 583-602, ensureTermAtLeast 635-641, joinLeaderInTerm 643-657, handleJoin 1267-1287 with handleJoinIgnoringExceptions 1289-1299, publish 1350 with the handleClientValue call at 1404, CoordinatorPublication.handlePublishResponse 1871-1875): https://github.com/opensearch-project/OpenSearch/blob/b2a54ba5c0defba3d1d20423e911d4bf920bab19/server/src/main/java/org/opensearch/cluster/coordination/Coordinator.java; CoordinationState (isPublishQuorum lines 156-158, handleStartJoin 213-255, handleJoin 264-339, handleClientValue 348-407, handlePublishRequest 416-460, handlePublishResponse 471-515, handleCommit 523-573) as transcribed by the OpenSearchCoordination mission: https://github.com/opensearch-project/OpenSearch/blob/b2a54ba5c0defba3d1d20423e911d4bf920bab19/server/src/main/java/org/opensearch/cluster/coordination/CoordinationState.java; the cluster model, the safety vocabulary and the inductive invariant of the OpenSearchSafety mission (Step, Reachable, Committed, Inv, reachable_inv); for why progress needs a stable period: M. J. Fischer, N. A. Lynch, M. S. Paterson, Impossibility of distributed consensus with one faulty process, J. ACM 32(2), 1985, and C. Dwork, N. Lynch, L. Stockmeyer, Consensus in the presence of partial synchrony, J. ACM 35(2), 1988
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: OpenSearchProgress.publication_acks_accepted

Notions used

The full expansions are in readback_Def_OpenSearchProgress.md.

Node-state notation. For a node state σ\sigmaσ:

  • cur(σ)\mathrm{cur}(\sigma)cur(σ) is the current term;
  • lat(σ)\mathrm{lat}(\sigma)lat(σ) and lav(σ)\mathrm{lav}(\sigma)lav(σ) are the term and version of the last accepted state;
  • won(σ)\mathrm{won}(\sigma)won(σ) is electionWon;
  • lpv(σ)\mathrm{lpv}(\sigma)lpv(σ) is lastPublishedVersion;
  • pv(σ)\mathrm{pv}(\sigma)pv(σ) is the list of ids in the publish votes.

P.dn(n)=⟨n,P.eligible(n)⟩P.\mathrm{dn}(n) = \langle n, P.\mathrm{eligible}(n)\rangleP.dn(n)=⟨n,P.eligible(n)⟩ is node nnn's discovery node.

Messages. A publication request publishRequest(src,s,pt,pv)\mathrm{publishRequest}(src, s, pt, pv)publishRequest(src,s,pt,pv) carries:

  • the publisher srcsrcsrc;
  • the published cluster state sss;
  • a ghost parent key (pt,pv)(pt, pv)(pt,pv), which is the publisher's accepted term and version when it published.

A publish response publishResponse(src,dst,⟨τ,v⟩)\mathrm{publishResponse}(src, dst, \langle \tau, v\rangle)publishResponse(src,dst,⟨τ,v⟩) goes from srcsrcsrc to dstdstdst and carries term τ\tauτ and version vvv. Messages are never removed.

The publication period PublicationExec(P,c,t,Q)(W,W′)\mathrm{PublicationExec}(P, c, t, Q)(W, W')PublicationExec(P,c,t,Q)(W,W′) is a finite, possibly empty, sequence of Steps. Each step is of one of the following kinds:

  • bootstrap of any node;
  • start-join at any node nnn, on a request from an eligible requester in term t′t't′, where t′≤tt' \le tt′≤t is required if n=cn = cn=c or n∈Qn \in Qn∈Q;
  • join: unrestricted;
  • client value, i.e. a new publication, by any node other than ccc;
  • publish: unrestricted, with no freshness guard;
  • respond: unrestricted;
  • commit: unrestricted;
  • restart of an eligible node other than ccc (members of QQQ may restart);
  • restartAny of a non-eligible node.

handlePublishRequest(σ, ⟨s⟩):

  • error if s.term≠cur(σ)s.\mathrm{term} \ne \mathrm{cur}(\sigma)s.term=cur(σ);
  • otherwise, if s.term=lat(σ)s.\mathrm{term} = \mathrm{lat}(\sigma)s.term=lat(σ) and s.version≤lav(σ)s.\mathrm{version} \le \mathrm{lav}(\sigma)s.version≤lav(σ):
    • error if s.term≠0s.\mathrm{term} \ne 0s.term=0;
    • if s.term=0s.\mathrm{term} = 0s.term=0 (the Zen1 branch), accept iff sss names a cluster-manager node that differs from the one in σ\sigmaσ's accepted state;
  • otherwise accept.

Accepting replaces σ\sigmaσ's accepted state by sss and returns ⟨s.term,s.version⟩\langle s.\mathrm{term}, s.\mathrm{version}\rangle⟨s.term,s.version⟩.

handlePublishResponse(σ, d, ⟨τ, v⟩):

  • error if won(σ)=false\mathrm{won}(\sigma) = \mathrm{false}won(σ)=false;
  • error if τ≠cur(σ)\tau \ne \mathrm{cur}(\sigma)τ=cur(σ);
  • error if v≠lpv(σ)v \ne \mathrm{lpv}(\sigma)v=lpv(σ);
  • otherwise the new publish-vote list is addVote(pv(σ),d).1\mathrm{addVote}(\mathrm{pv}(\sigma), d).1addVote(pv(σ),d).1, which prepends d.idd.\mathrm{id}d.id if ddd is flagged cluster-manager and d.idd.\mathrm{id}d.id is not yet present. The handler also returns an apply-commit request when the votes are a quorum of σ\sigmaσ's last committed and last published configurations.

1. Declaration

The universally quantified variables and hypotheses, in order:

NameType / statement
V (implicit)Type
PParams
hPP.InitCompatibleP.\mathrm{InitCompatible}P.InitCompatible
hesP.strategy=DEFAULT_INSTANCEP.\mathrm{strategy} = \mathrm{DEFAULT\_INSTANCE}P.strategy=DEFAULT_INSTANCE
WCluster V (start of the period)
hWReachable(P,W)\mathrm{Reachable}(P, W)Reachable(P,W)
cnode id (the cluster-manager)
tN\mathbb{N}N (its term)
Qlist of node ids (acknowledging nodes)
hQ∀q∈Q, P.eligible(q)=true\forall q \in Q,\ P.\mathrm{eligible}(q) = \mathrm{true}∀q∈Q, P.eligible(q)=true
hwonwon(W.node c)=true\mathrm{won}(W.\mathrm{node}\ c) = \mathrm{true}won(W.node c)=true
hctcur(W.node c)=t\mathrm{cur}(W.\mathrm{node}\ c) = tcur(W.node c)=t
sClusterState V
ptN\mathbb{N}N
pvZ\mathbb{Z}Z
hspublishRequest(c,s,pt,pv)∈W.sent\mathrm{publishRequest}(c, s, pt, pv) \in W.\mathrm{sent}publishRequest(c,s,pt,pv)∈W.sent
hsts.term=ts.\mathrm{term} = ts.term=t
hsvs.version=lpv(W.node c)s.\mathrm{version} = \mathrm{lpv}(W.\mathrm{node}\ c)s.version=lpv(W.node c)
W'Cluster V
hEPublicationExec(P,c,t,Q)(W,W′)\mathrm{PublicationExec}(P, c, t, Q)(W, W')PublicationExec(P,c,t,Q)(W,W′)

Conclusion. The conclusion is the conjunction of (A) and (B).

(A)

∀q∈Q, cur(W′.node q)=t→(publishResponse(q,c,⟨t,s.version⟩)∈W′.sent  ∨  ∃ cs′ r, handlePublishRequest(W′.node q,⟨s⟩)=ok(cs′,r)).\forall q \in Q,\ \mathrm{cur}(W'.\mathrm{node}\ q) = t \to \Big(\mathrm{publishResponse}(q, c, \langle t, s.\mathrm{version}\rangle) \in W'.\mathrm{sent} \;\lor\; \exists\, cs'\ r,\ \mathrm{handlePublishRequest}(W'.\mathrm{node}\ q, \langle s\rangle) = \mathrm{ok}(cs', r)\Big).∀q∈Q, cur(W′.node q)=t→(publishResponse(q,c,⟨t,s.version⟩)∈W′.sent∨∃cs′ r, handlePublishRequest(W′.node q,⟨s⟩)=ok(cs′,r)).

Unfolded: let σq=W′.node q\sigma_q = W'.\mathrm{node}\ qσq​=W′.node q, with cur(σq)=t=s.term\mathrm{cur}(\sigma_q) = t = s.\mathrm{term}cur(σq​)=t=s.term. If t≥1t \ge 1t≥1, the handler succeeds exactly when ¬(lat(σq)=t∧s.version≤lav(σq))\neg(\mathrm{lat}(\sigma_q) = t \land s.\mathrm{version} \le \mathrm{lav}(\sigma_q))¬(lat(σq​)=t∧s.version≤lav(σq​)). If t=0t = 0t=0, the Zen1 branch could also accept. A reachable cluster with a sent publication of term ttt has t≥1t \ge 1t≥1, which I derived from the step relation; the statement does not say it. So (A) says: every member of QQQ that is in term ttt at W′W'W′ and has already accepted a term-ttt state of version ≥s.version\ge s.\mathrm{version}≥s.version has sent ccc the acknowledgement ⟨t,s.version⟩\langle t, s.\mathrm{version}\rangle⟨t,s.version⟩. Every other member of QQQ in term ttt can accept sss now.

(B)

∀q∈Q, publishResponse(q,c,⟨t,s.version⟩)∈W′.sent→∃ cs′ o, handlePublishResponse(W′.node c,P.dn(q),⟨t,s.version⟩)=ok(cs′,o)∧q∈cs′.publishVotes.nodes.\forall q \in Q,\ \mathrm{publishResponse}(q, c, \langle t, s.\mathrm{version}\rangle) \in W'.\mathrm{sent} \to \exists\, cs'\ o,\ \mathrm{handlePublishResponse}(W'.\mathrm{node}\ c, P.\mathrm{dn}(q), \langle t, s.\mathrm{version}\rangle) = \mathrm{ok}(cs', o) \land q \in cs'.\mathrm{publishVotes}.\mathrm{nodes}.∀q∈Q, publishResponse(q,c,⟨t,s.version⟩)∈W′.sent→∃cs′ o, handlePublishResponse(W′.node c,P.dn(q),⟨t,s.version⟩)=ok(cs′,o)∧q∈cs′.publishVotes.nodes.

Unfolded: let σc=W′.node c\sigma_c = W'.\mathrm{node}\ cσc​=W′.node c. The handler's guards say won(σc)=true\mathrm{won}(\sigma_c) = \mathrm{true}won(σc​)=true, cur(σc)=t\mathrm{cur}(\sigma_c) = tcur(σc​)=t and lpv(σc)=s.version\mathrm{lpv}(\sigma_c) = s.\mathrm{version}lpv(σc​)=s.version. The membership q∈addVote(pv(σc),P.dn(q)).1q \in \mathrm{addVote}(\mathrm{pv}(\sigma_c), P.\mathrm{dn}(q)).1q∈addVote(pv(σc​),P.dn(q)).1 then holds automatically, because P.dn(q)P.\mathrm{dn}(q)P.dn(q) is flagged cluster-manager by hQ. So (B) amounts to: if at least one member of QQQ has acknowledged sss to ccc by W′W'W′, then at W′W'W′ the node ccc is still elected, still in term ttt, and its last published version is still s.versions.\mathrm{version}s.version.

2. What is not constrained

  • ccc's eligibility. It is not assumed. In a reachable cluster only eligible nodes ever have won=true\mathrm{won} = \mathrm{true}won=true, so hwon implies it. I derived this from the step relation: joins are addressed only to eligible requesters.
  • No quorum or term hypothesis on QQQ.
    • Members of QQQ that are not in term ttt at W′W'W′ are not covered by (A).
    • Members above ttt at WWW stay above ttt, since start-joins only raise terms and eligible nodes keep their term on restart. They are never covered.
    • Members below ttt need a start-join into ttt first. The period allows it (t′≤tt' \le tt′≤t), and handleStartJoin's only guard is the term comparison, but the theorem does not state that this step is enabled.
  • The ghost parent. ptptpt and pvpvpv are unconstrained apart from hs.
  • Scope of (A).
    • In (A), the acknowledgement may have been sent before WWW.
    • (A)'s second disjunct is about the pure handler applied to qqq's state. The corresponding publish step, for the message (c,s,pt,pv)(c, s, pt, pv)(c,s,pt,pv), is available at W′W'W′ because sent only grows and the publication period puts no guard on publish.
  • Scope of (B).
    • (B) is triggered only by an existing acknowledgement from a member of QQQ. If no member of QQQ has acknowledged, it says nothing about ccc.
    • Acknowledgements from non-members, or with other versions, are not addressed.
    • (B) implicitly asserts that ccc cannot lose electionWon while it handles further joins during the period. Java asserts this (CoordinationState.java:323). Nothing in the Lean handlers enforces it, so it must follow from reachability under the default strategy (hes).
  • No quorum or commit claim. Neither conjunct says that a quorum of acknowledgements is reached, or anything about commits.
  • Model-relative. In the model, every successful handlePublishRequest sends an acknowledgement, and that acknowledgement stays deliverable. In Java, a failing remote-store write makes the method throw after the local acceptance (CoordinationState.java:453-456), so no acknowledgement is sent. The Coordination file abstracts this away; see G5 in the definitions read-back. In that case neither disjunct of (A) would hold for that voter in OpenSearch: no acknowledgement exists, and re-handling sss is rejected because the version is not newer.
  • Role of hsv. hsv pins sss as ccc's latest publication at WWW. Its version is the one that ccc's handler accepts in acknowledgements.
  • What the period still allows. During the period:
    • nodes outside {c}∪Q\{c\} \cup Q{c}∪Q may move to any term, win, and publish;
    • members of QQQ may restart, bootstrap (if the contract allows), and accept any publication of their current term;
    • only ccc is barred from publishing further.
  • Empty execution and vacuity.
    • The empty execution (W′=WW' = WW′=W) is allowed, and then the theorem is a statement about WWW itself.
    • If Q=[ ]Q = [\,]Q=[], both conjuncts are vacuous.
    • The hypotheses are satisfiable. Single-node example: node 1 is eligible, the bootstrap configuration is {1}\{1\}{1} only, and the strategy is the default. Node 1 bootstraps, start-joins on its own request for term 1, handles its own join (and wins), and publishes sss of term 1 and version 1. Then WWW is the cluster right after the publication, with c=1c = 1c=1, t=1t = 1t=1 and Q=[1]Q = [1]Q=[1].

3. Plain-language summary

Suppose that, in a reachable cluster, ccc has won term ttt and has sent sss as its latest publication. Then, throughout any stable publication period, the following hold:

  • In this period no node of {c}∪Q\{c\} \cup Q{c}∪Q moves above ttt, ccc neither publishes again nor restarts, and everything else may happen.
  • Every eligible member of QQQ that is in term ttt has either already acknowledged sss to ccc, or can still accept sss.
  • As soon as a member of QQQ has acknowledged sss to ccc, ccc can still count that acknowledgement.

The theorem covers only members of QQQ already in term ttt. It does not claim that acknowledgements are sent, that a quorum is reached, or that anything is committed.

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