Path summary: across uncommitted publications, an accepted configuration stays in force
ProvedOpenSearchSafety.inv_lineageFor all P, every cluster W with Inv P W and two sent publications W.sent (.publishRequest srcD sD ptD pvD) and W.sent (.publishRequest srcE sE ptE pvE) such that
Descends W sD.term sD.version sE.term sE.versionand¬ (sD.term = sE.term ∧ sD.version = sE.version), and- no committed key lies strictly between them: every committed
(ft, fv)withDescends W sD.term sD.version ft fvandDescends W ft fv sE.term sE.versionis(sD.term, sD.version)or(sE.term, sE.version),
we have sE.lastCommittedConfiguration = sD.lastAcceptedConfiguration ∨ sE.lastAcceptedConfiguration = sD.lastAcceptedConfiguration.
The last committed configuration is copied from the parent unless the parent is committed, and the last accepted configuration changes only when the last committed configuration is the parent's last accepted one (pub_parent, the transcription of handleClientValue's reconfiguration guard and of the asserted copying of the committed configuration). Hence at most one reconfiguration is in flight between commits: the configuration accepted at D is one of the two configurations of every publication E that descends from D, with a different key and no committed key strictly between them (D and E themselves may be committed).
import Definitions.Def_OpenSearchSafety open OpenSearchCoordination OpenSearchSafety
theorem OpenSearchSafety.inv_lineage {V : Type} (P : Params) (W : Cluster V) (hinv : Inv P W)
(srcD srcE : NodeId) (sD sE : ClusterState V) (ptD ptE : Nat) (pvD pvE : Int)
(hD : W.sent (.publishRequest srcD sD ptD pvD)) (hE : W.sent (.publishRequest srcE sE ptE pvE))
(h : Descends W sD.term sD.version sE.term sE.version)
(hne : ¬ (sD.term = sE.term ∧ sD.version = sE.version))
(hint : ∀ ft fv, Committed W ft fv → Descends W sD.term sD.version ft fv → Descends W ft fv sE.term sE.version →
(ft = sD.term ∧ fv = sD.version) ∨ (ft = sE.term ∧ fv = sE.version)) :
sE.lastCommittedConfiguration = sD.lastAcceptedConfiguration ∨
sE.lastAcceptedConfiguration = sD.lastAcceptedConfiguration := 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: OpenSearchSafety.inv_lineage
Notions used
Model and notation. Node ids are natural numbers. The parameters consist of an eligibility function (write for , " is cluster-manager-eligible"), a predicate on voting configurations (the bootstrap configurations; it may be empty or have any number of elements), and an election strategy . is the discovery node with id and cluster-manager flag .
A voting configuration is a strictly increasing list of node ids, so two configurations are equal exactly when they contain the same ids; is the empty one. For a list of node ids, " is a quorum of ", Lean c.hasQuorum q = true, means
i.e. strictly more than half of the members of occur in ; the order of , repetitions in and members of outside are irrelevant, and has no quorum at all.
A cluster state has a term , a version , a metadata version, a last committed configuration , a last accepted configuration , an optional cluster-manager id, two Boolean cluster-UUID flags, and a payload of the arbitrary type . A key is a pair ; the key of is .
A cluster consists of a coordination state for every natural number and a predicate on messages ("has been sent"); for an arbitrary the sent messages form an arbitrary, possibly infinite, set. Messages are of four kinds:
- , where a join consists of a source discovery node and a target discovery node (each an id and a flag), a term , a last accepted term and a last accepted version ;
- (Lean
.publishRequest src s pt pv), a publish request from node carrying the cluster state and the ghost parent key ; - , a publish response from node to node for the key ;
- , an apply-commit request with source discovery node and key .
A publication is a sent message ; its key is the key of and its parent is . In the model's steps, a node publishes , so the ghost parent is the publisher's accepted key at publication time; but the statements below are about arbitrary clusters satisfying the invariant, where only the invariant constrains .
For a node , read off its coordination state : its local discovery node; its current term; , , , the term, version, last committed and last accepted configuration of its last accepted state; its election-won flag; its started-join-since-last-reboot flag; and its last published version and configuration; and the node-id lists of its join votes and publish votes.
Committed keys. (Lean Committed W t v) holds iff some message has been sent, for some source discovery node . The definition alone does not require to be the key of a publication.
Parent and descent. holds iff some publication has been sent with : a publication of key whose ghost parent is . Descent, Lean Descends W t v t' v', written here and read " descends from " — the first key is the ancestor — is the least relation that is reflexive on every key and closed under appending a step: iff there is a chain with and for each . It is reflexive on every key, published or not; a key that is not the key of any publication has no ancestor but itself. "Proper" descent means between two different keys. For a publication write .
Auxiliary relations (over and ):
- : — the lexicographic order on keys.
- : — lexicographic, except that versions are not compared when both terms are .
- , for configurations (in the role of a last committed configuration) and (last accepted): either (i) , and , with unconstrained; or (ii) some publication has key , , and either or ( and ).
- , for a list of node ids: every has and there is a sent with , and .
- : the same, and moreover that join satisfies .
- : every has and has been sent for some node (any destination).
- : , , , is a quorum of and is a quorum of . The key is the base. (Since is a quorum of , and are non-empty; nothing requires to have won or published, nor the base to be published.)
- : , and either ( and ) or some publication from has .
The voter lists may be empty (the voter conditions then hold vacuously) and may contain repetitions.
The invariant is the conjunction of the following 30 fields (node variables range over all of ; "sent" means in ; is descent as above).
Every node :
localNode_eq: .idle_of_not_won: .won_started: .votes_started: .started_term_pos: .won_quorum: is a quorum of and of .not_won_no_quorum: is a quorum of and of .joinVotes_sent: every has , and some sent has , , and .publishVotes_sent: every has , and has been sent.
Every eligible node ():
term_le: .accepted_realizes: or .
Joins and publish responses:
join_wf: every sent has and .join_term_le: every sent with has .join_unique: two sent joins with the same source id, that source eligible, and the same term are equal (all five fields, so in particular the same target).join_after_response: for a sent and a sent with , and : .response_le: for a sent with : and .response_published: for every sent there is a sent publication from with key .
Publications — for every sent :
pub_wf: , , , , and .pub_parent: if , there is a sent with key such that (a) , or ( and ); and (b) .pub_unique: any two sent publications with the same key are the same message (same source, same cluster state in all fields, same parent).pub_rooted: for some .pub_same_term: for every sent with : or .pub_voters: some list with is a quorum of and of .pub_election: if , then for some configuration and list .
Commits:
commit_quorum: for every sent there are a sent with key and a list with , a quorum of , and either a quorum of , or ( and some sent publication of key has last accepted configuration ).
Leaders:
won_unique: .pub_source_term: for every sent : , or and ( or ).leader_pubs: if , every sent with (any source) has , , and a quorum of and of .leader_inflight: if and , then for some state : is sent, , , , and either , or (, and ).leader_settled: if and , then either ( and ), or ( and no sent publication has term ).
1. Declaration
Binders and hypotheses, in order:
- A type (implicit), parameters , a cluster over , and
hinv: . - Node ids ; cluster states ; ; .
hD: has been sent (publication );hE: has been sent (publication ).h: .hne: .hint: for all , if , and , then or — no committed key lies strictly between and .
Conclusion.
If publication properly descends from publication and no key strictly between them is committed, then 's last accepted configuration reappears in , as 's last committed configuration or as 's last accepted configuration.
2. What is not constrained
- and themselves may or may not be committed (
hintexcludes only strictly intermediate committed keys). - Sources and parents of and are free; is not mentioned.
- When the second disjunct holds nothing is said about , and conversely.
hintis satisfiable with content, for example when nothing at all is committed (then it holds vacuously and the conclusion is still asserted).
The hypothesis . The statement is about every cluster satisfying the 30 fields, for arbitrary parameters (any eligibility function, any bootstrap-configuration predicate, any election strategy) and any payload type . Reachability is not assumed, and is not assumed. The hypothesis is satisfiable, so the statement is not vacuous on that account: every cluster in which no message has been sent and every node is in the state for some state of term with empty configurations (the model's Initial clusters) satisfies all 30 fields — fields 1, 2, 10 and 11 by direct check, field 7 because has no quorum, the rest vacuously. On such clusters the conclusion is trivial. That clusters with publications and commits satisfy the invariant is the subject of other stubs (reachable_inv, which assumes P.InitCompatible and the default election strategy, and commit_reachable), not of this statement. Neither the statement nor mentions .
3. Plain-language summary
In any cluster satisfying the invariant, if publication properly descends from publication with no committed key strictly between them, then 's last accepted configuration is either 's last committed configuration or 's last accepted configuration.
Confirmed by the mission captain (proposal self-audit).
Confirmed by the moderator at approval.