Sal is a Lean 4 framework for verifying state-based CRDTs and Mergeable Replicated Data Types (MRDTs) under replication-aware (RA) linearizability. Rather than discharging every verification condition with a single backend, Sal stages automation by trustworthiness: it first attempts kernel-verified proof reconstruction, falls back to an SMT backend only when that fails, and finally hands remaining obligations to an AI-assisted interactive theorem prover — all while keeping the trusted computing base (TCB) as small as the VC allows. When a VC is in fact invalid, Sal uses Plausible (property-based testing) together with a ProofWidgets-based visualizer to turn the failure into an inspectable counterexample execution trace.
The approach builds on the F★-based Neem framework of Soundarapandian, Nagar, Rastogi, and Sivaramakrishnan (OOPSLA 2025), which reduces RA-linearizability for a data type to a fixed set of VCs over do, merge, and rc. Sal is the Lean port of that reduction plus a multi-modal tactic, counterexample pipeline, and custom decidable set/map interfaces that make grind effective on RDT goals.
The suite currently contains 29 RDTs — 17 CRDTs and 12 MRDTs — with all 24 RA-linearizability VCs closed on every RDT the standard VC schema applies to. Two MRDTs sit outside that count for different reasons: Enable_Wins_Flag_known_broken is an intentionally-buggy demo fixture, and the tombstone-free RGA is provably outside the schema (its commutation only holds conditioned on reachable states) — it instead carries a direct, kernel-checked end-to-end theorem: RA-linearizability up to observational equivalence at every reachable configuration, under an honest-delivery assumption (see the metatheory entry below). That's 648 VCs for state convergence (27 × 24), of which the vast majority are kernel-checked (no TCB-enlarging admits) and a small residue of stage-2 Blaster-admits remain in a few files (OR_Set_MRDT, OR_Set_Efficient_MRDT, Add_Win_Priority_Queue_MRDT, Multi_Valued_Register_MRDT) — validated by Z3 via the sal tactic's SMT stage but not yet kernel-reconstructed.
Every RDT carries a *_ReadSide.lean companion (and a *_SPOT.lean of small concrete-execution tests) alongside its *_CRDT.lean / *_MRDT.lean. The Tier-C RDTs (Peritext, RGA, Add_Win_Priority_Queue, OR_Set plain and efficient, Multi_Valued_Register, LWW_Element_Set) carry substantive intent-preservation theorems matching paper claims; the Tier-A RDTs carry mechanical 30–60 line files documenting the obvious read so a reader can confirm at a glance that it is in fact obvious. Per-RDT crosswalks for the Tier-C papers:
docs/peritext-vs-paper.md— Litt et al. CSCW 2022, Ex 1 / 2 / 3 / 5 / 7 / 8 intent-preservation.docs/rga-vs-paper.md— Roh et al. JPDC 2011, causal-order preservation, tombstone monotonicity, deterministic concurrent-insert tiebreak.docs/aw-crpq-vs-paper.md— Zhang et al. Internetware 2023, Add-wins headline + LWW innate + acquired-Σ +get_max.docs/or-set-vs-paper.md— Shapiro et al. INRIA RR-7506, Add-Wins on lookup with sequential-Add-then-Remove extinguishment.docs/mvr-vs-paper.md— Shapiro et al. INRIA RR-7506 §3.2.2, classical replace-on-write semantics with concurrent-writes-both-survive + sequential-writes-supersede.docs/lww-element-set-vs-paper.md— Shapiro et al. INRIA RR-7506 §3.3.4, LWW-comparison lookup withlookup_after_add_with_fresh_ts+remove_at_higher_ts_extinguishes.
The methodology — the Tier-A/B/C distinction, when read-sides are needed, the snapshot-in-op-payload pattern, and the spec-validation lesson from in_span_boundary — is documented in docs/readside-projections.md.
Everything is checked on Lean v4.28.0 against the chore-bump-lean-4.28 branch of a Blaster fork.
CRDTs (Sal/CRDTs/)
Registers & counters:
Increment_Only_CounterPN_CounterLWW_RegisterMAX_RegisterMIN_RegisterMulti_Valued_Register— classical replace-on-write MVR via the snapshot-in-op-payload trick (Shapiro et al. INRIA RR-7506 §3.2.2). State(writes, removed); concurrent writes survive via additive merge, sequential writes overwrite via the snapshot. + read-side:is_visible_value,concurrent_writes_both_visible,sequential_write_supersedes. Seedocs/mvr-vs-paper.md.Bounded_Counter— Sypytkowski 2019 / Balegas et al. 2015. PN-counter plus a sparse per-replica-pairtransfersmap for quota redistribution.
Sets & maps:
OR_Set— Shapiro et al. INRIA RR-7506. + read-side:lookup,add_wins_over_concurrent_remove,add_then_remove_extinguishes. Seedocs/or-set-vs-paper.md.Grow_Only_SetGrow_Only_MultisetLWW_Element_Set— Shapiro et al. INRIA RR-7506. Per-element latest-add-ts and latest-remove-ts maps;lookupuses strict->comparison (remove-wins on tie). + read-side:lookup_after_add_with_fresh_ts,remove_at_higher_ts_extinguishes(independent intent theorems);lookup_def(definitional unfolding oflookup, not a behavioural guarantee — renamed fromlatest_write_wins, which overstated it). Seedocs/lww-element-set-vs-paper.md.LWW_MapMAX_Map
Sequences & structured data:
RGA— Replicated Growable Array, the sequence CRDT underlying Automerge / Yjs, in its state-based formulation as a grow-onlyMap OpId (char, afterId, deleted). + read-side:visible_ltfour-rule DFS-traversal predicate,causal_order_visible_lt,tombstone_monotone_under_remove,concurrent_insert_tiebreak_deterministic. Seedocs/rga-vs-paper.md.Peritext— Litt et al. CSCW 2022. Rich text = RGA + formatting marks represented as a flatset AnchorAttachment. + read-side: paper Ex 1 / 2 / 3 / 5 / 7 / 8 intent-preservation theorems (kernel-checked, mirrored on the MRDT side). Seedocs/peritext-vs-paper.md.Shopping_CartAdd_Win_Priority_Queue— adapted from Zhang et al. 2023. + read-side:lookup,add_wins_over_concurrent_rmv, LWW innate, MCW-collapsed-to-Σ acquired,get_max,inc_increases_acquired. Seedocs/aw-crpq-vs-paper.md.
MRDTs (Sal/MRDTs/)
Increment_Only_CounterPN_CounterMulti_Valued_Register— classical MVR with the same(writes, removed)shape as the CRDT but standard three-way merge per component. + read-side (mirrors the CRDT side). Seedocs/mvr-vs-paper.md.Grow_Only_SetGrow_Only_MapOR_Set— + read-side (mirrors the CRDT side via three-way merge). Seedocs/or-set-vs-paper.md.OR_Set_Efficient— compressed variant with(rid, ts, elem)triples and per-replica deduplication. + read-side with the same headline theorems on the triple representation.Replicated_Growable_Array— the tombstoned MRDT RGA (Sal/MRDTs/RGA_with_tombstones/). + read-side with relationalreadSeq_visibleand the three RGA intent theorems. Seedocs/rga-vs-paper.md.RGA_Tombstone_Free— the rehoming RGA (Sal/MRDTs/RGA_Rehoming/; formerly holding the plain nameRGA/, demoted 2026-07-16): the tombstone-free, path-carrying RGA: deletes really remove (no tombstone set); each op carries its target's recorded ancestor path, and merge rehomes survivors along it. Status: its convergence capstone is sound, but itsdois sequential-spec-refuted — deleting an interior node reorders survivors on a single replica (tombstone_free_violates_delete_order, and in campaign formrehoming_seq_refuted), so it does not implement the naive text buffer. Retained as the framework's generality stress test and the delete-order countermodel; the recommended sequence datatype is the embedded-chain family (RGA_Embed/EmbedRGA, seq-spec-sound and read-equal to the published RGA). Provably outside the standard 24-VC schema (commutation is reachability-conditioned, and a prefix-free variant is impossible —RGA_PrefixFree_Impossible.lean); verified instead by a direct end-to-end theorem,rga_ra_linearizable3_eq: RA-linearizability up to observational≈at every reachable configuration under honest delivery, via the applicability-conditioned metatheory (Sal/ConditionedMRDTs/MRDT_Instances/RGA_Rehoming/RA_Lin.lean). An eq-variant (RGA_Tombstone_Free_Eq_MRDT.lean) shows the≈is purely representational: a normalizing delete pins ghost payloads to the default, on normal forms the observational equivalence is structural equality, and the variant's folds are the normal forms of the original's. SeeSal/MRDTs/RGA_Rehoming/doc/why-the-path-matters.pdf.Add_Win_Priority_Queue— adapted from Zhang et al. 2023. Drops the CRDT's tombstone set since the LCA handles Add-Wins directly, leavingset (add_ts, elem, value) × set (inc_ts, elem, amount). + read-side. Seedocs/aw-crpq-vs-paper.md.Peritext— Litt et al. CSCW 2022. RGA substrate plusset AnchorAttachment. RGA's tombstones are structurally load-bearing (later inserts reference earlier char ids), so this MRDT keeps all components grow-only and uses pointwise-union merge, mirroringRGA_MRDT. + read-side: the kernel-checked paper Ex 1 / 2 / 3 / 5 / 7 / 8 intent-preservation theorems (Sal/MRDTs/Peritext_with_tombstones/Peritext_ReadSide.lean). Seedocs/peritext-vs-paper.md.Enable_Wins_Flag— enable-wins boolean flag, per-replica map of(counter, flag).Enable_Wins_Flag_known_broken— intentionally buggy variant preserved as a demo fixture. Drives the Plausible counterexample demo; the bug manifests oninter_right_1op.
The tactic lives in Sal/Tactic/Sal.lean and tries three strategies in order, stopping at the first one that succeeds:
dsimp+grind— lightweight SMT-style automation with proof reconstruction; the result is a kernel-checkable proof term. This stage is preferred because it does not enlarge the TCB. We deliberately skipaesopat this stage because its verification times on these RDT goals were prohibitive.lean-blaster— encodes the goal to Z3. More powerful (especially for higher-order functions and lambdas) but sacrifices proof reconstruction, so the TCB grows to include the SMT solver. Invoked with a wall-clock timeout (default 30 s) so a stuck goal cannot hang.dsimp+aesop+all_goals (try grind)— a broader proof-search fallback. Remaining goals are then typically closed interactively with tactics produced by Harmonic's Aristotle, whose outputs are kernel-checked so the TCB is still not enlarged.
Stages 1 and 3 are guarded against sorryAx in the resulting proof term: aesop's default mode can otherwise close a goal with a silent sorry placeholder. Stage 2 is intentionally not guarded, because Blaster trusts Z3's "valid" verdict via MVarId.admit — that is Blaster's TCB-enlarging mechanism.
The tactic takes a heartbeat budget (default 400 000) that caps Lean-side elaboration across all three stages, and a separate smtTimeoutSec budget (default 30 s) for the SMT stage. See the docstring in Sal.lean for how to tune them.
Minimal example (see Sal/Tactic/SalExample.lean for more):
import Sal.Tactic.Sal
example (a b : Nat) : a + b = b + a := by salMany post-paper CRDTs in the suite are proved with a uniform kernel-verifiable pattern — rcases over the operation family, refine ⟨?_, …, ?_⟩ to split the state's components, then simp +decide [*] and grind — and avoid Blaster entirely. A few stubborn VCs still need Blaster or an Aristotle-assisted intermediate lemma (e.g. LWW_Map_CRDT uses merge_do_lex_max); those calls stay inside the three-stage pipeline. For the full recipe of translating an op-based CRDT into Sal's state-based signature and closing the 24 VCs, see docs/porting-op-based-crdts.md.
Lean's standard Set α := α → Prop is convenient for hand-written proofs but fights automation (membership is a proposition, not a Boolean). Sal introduces decidable versions where grind can compute:
abbrev set (a : Type) [DecidableEq a] := a → Bool
structure map (key : Type) [DecidableEq key] (value : Type) where
mappings : key → value
domain : set keyEvery lemma on these types is annotated with @[simp, grind] and (where useful) a grind_pattern, building a domain-specific rewrite database that lets grind discharge set/map goals without SMT assistance. Files live in Sal/Interfaces/.
The Boolean-predicate representation is grind-friendly only as a top-level state component. Nesting a set inside a map value — e.g. map K (set V) — forces grind to prove function equality via funext and typically defeats it. Where possible, flatten: represent map K (set V) as set (K × V). The Peritext CRDT is the clearest example in the suite: its formatting marks were originally a map (OpId × Bool) (set MarkOp), which left 5 of 24 VCs stuck; flattening to a top-level set AnchorAttachment closes all 24.
When automation fails because the implementation is actually wrong, Sal makes the failure inspectable rather than opaque:
- Plausible generates concrete counterexamples for decidable VCs. The canonical demo is the Enable-Wins Flag MRDT, which contains a known bug from prior work (the
inter_right_1opVC fails); Plausible rediscovers a minimal failing execution automatically. SeeSal/Counterexample_Visualization/WriterMonad_Enable_Wins_Flag.lean. - ProofWidgets trace visualizer. A logging-style writer monad instruments
doandmergeto record intermediate states, and a ProofWidgets component renders the LCA, left branch, right branch, and merge result as a vertical diagram. SeeSal/Counterexample_Visualization/. - Universe tracking for functional sets. Since Sal's
settype is aα → Boolpredicate and may be infinite, the visualizer augments abstract sets with a concreteHashSetof elements added or removed during execution, so the state can be displayed concretely.
Clone this repository, then install elan (the Lean toolchain manager). elan will read lean-toolchain and install Lean v4.28.0 on first use. From the repo root, run lake exe cache get to download the prebuilt Mathlib oleans — this takes a few minutes and is required before any file will type-check in a reasonable time.
lake update is safe to run — lakefile.toml pins mathlib to v4.28.0 and pins Blaster to the chore-bump-lean-4.28 branch of kayceesrk/Lean-blaster, a fork whose upstream (input-output-hk/Lean-blaster) does not yet have a v4.28-compatible branch. Once the upstream catches up we will switch back.
Open each Lean file in VS Code to run the verification conditions interactively, or run lake lean <path-to-file.lean> from the command line. The run_files.sh script checks every .lean file under a given directory.
Browser demos live in demos/ (Vite + React + TypeScript, one hand-ported module per RDT). 28 of the 29 RDTs have a playground — 17 CRDTs + 11 MRDTs (the tombstone-free RGA does not have one yet).
- CRDT playgrounds spin up three replicas, let you apply local ops per replica, and merge any pair directionally (source → target, like
git merge). There's also a "Merge all" button that folds every replica's state into a single join and assigns it back, so you can watch replicas snap to the same value in one click. Toggle Show concrete state to expose the lattice representation. - MRDT playgrounds organise history like git. Every local op creates a 1-parent commit; every merge creates a 2-parent commit with the LCA computed from the DAG (BFS on ancestors). A toggleable SVG history graph shows per-replica lanes with colour-coded commits (op commits solid, merge commits dashed, HEADs ringed thicker); click any past commit to inspect its full state.
- Lattice-law invariants are property-checked with fast-check per RDT: CRDTs get idempotence / commutativity / associativity / strong convergence; MRDTs get left identity / right identity / commutativity (the MRDT
merge(l,a,a) ~ aanalog is NOT a law — the closed-form counter MRDT violates it by design; MRDTs only promise convergence given a coherent history DAG, which the playground supplies at runtime).
cd demos
npm install
npm run dev # http://localhost:5173
npm run test # 28 fast-check suites, ~1.5 s
npm run build # TS + Vite production bundleSee demos/README.md for the CRDTSpec / MRDTSpec interfaces, file layout, and deployment. .github/workflows/demos-deploy.yml publishes to GitHub Pages on every push to main that touches demos/**.
-
Sal/Interfaces/— Sal's decidablesetandmapinterfaces (Set_Extended,Map_Extended,Map_Extended_With_Lean_Set). -
Sal/Tactic/— thesaltactic (Sal.lean) and usage examples (SalExample.lean). -
Sal/CRDTs/— 17 state-based CRDTs in the⟨Σ, σ₀, do, merge, rc⟩signature. -
Sal/MRDTs/— 12 state-based MRDTs. -
Sal/Counterexample_Visualization/— theWriterMonad_*.leanlogging-monad traces that feed the ProofWidgets visualizer. -
demos/— Vite + React + TypeScript playgrounds, one per RDT. CRDT demos do two-way merge; MRDT demos maintain a git-style commit DAG with LCA-driven three-way merge and a toggleable history visualisation. -
runtime/— the JS MRDT runtime (task #94): a git-like commit DAG for the browser (dependency-free ESM), replicas enforcing head-sync by construction, LCA-driven three-way merge with an explicit criss-cross gate (multiple maximal common ancestors throw, pointing at the virtual-LCA extension, task #90; routine under honest p2p: 592 gated syncs in 220 randomized trials — and the model side of #90 has since landed (virtual-lca-note.md+VirtualLCA_Spot.lean):Step3Vwith the ungatedmergeVirtualrule (recursive antichain mergevirtualLCAState, well-founded, ascending rank), the covering propositionmca_events_cover(the MCA union is exactly the head intersection, under the store invariants already carried), canonicityvirtualLCAState_canonical(so the per-datatype VC surface does not move for canonicity datatypes), RA-linearizability on the widened LTS (ra_linearizable3_of_honest_reachV), and the revised GCgc_safetyVwith themcasClosurekeep-set (the one-layer seed provably loses a depth-2 LCA); single-MCA picks are machine-refuted (each resurrects a deleted element, the SPOT FAIL pair); the runtime's gate remains until the JS implements virtual merges plus the closure seed. The quotient-layer mirrors have since landed as well (GoodConfig3H_V.lean: ONE H-layer fold induction sufficed — the Eq-quotient layers contain no step destructs, and the NF route is precisely the refuted noopFeasible path, deliberately not built — giving the rehoming Eq capstone over the widened LTS,rga_ra_linearizable3_eq_V, and all eleven flats through one bridge,flat_ra_linearizable3_eq_V; the route was forced by a Python probe,rehoming-vlca-probe.md, which found the hEnum shape fires at antichain unions under every enumeration order yet is rehome-correct at every firing, so noopFeasible marks a dead proof route and the mirrors go through K1/GenDisc). And the stability layer is now verified (Stability_VC.lean, design + validation instability-vc-note.md): theSettledAtcontract (the naive meet-of-heads gate is machine-refuted by the discriminating-remove countermodel, fired in the Python harness and pinned as a kernel SPOT), theStabilityVCbundle with an Aux-indexed merge congruence, andstability_simulationat {propext, Quot.sound} — compaction projects to a stuttering self-merge, so the twin DAGs stay literally identical — with reads equal at every version and RA-linearizability inherited observationally; first instance the OR-set (ORSet_stability_reads/ORSet_stability_ra: the twin-liveness-guarded drop — a static drop set is pinned unsound), and the embed re-coding cluster bridged toSettledAtup to the namedAnchorsFactorBeyondresidue (EmbedRGA_Stability_Bridge.lean)), and the commit GC implementing the verified keep-set:gc_safety(Metatheory/GC_Safety.lean, kernel-clean; design noteruntime-gc-note.md) proves pruning to the upward closure of the pairwise head intersections preserves every run and every head read, with a machine-checked countermodel showing a widened (non-head-sync) merge genuinely needs a pruned commit, and the head-monotonicity invariant corrected toHeadDom ∨ Virgin(fresh replicas rebase at the root). Datatype ports: the embedded-chain RGA (pluggable delta code, default = the verified flipped Elias-δ instance transliterated from Lean, 8.9× smaller than unary on the growing-delta workload, code-invariance tested: identical reads under both codes across 100 randomized runs) and an OR-set; the ports are unverified transliterations pinned by Lean codeword pins, Python-extracted read fixtures (both fooling-pair worlds ride through the runtime), and a twin-run GC-safety PBT (220+120 trials, per-step read equality against un-GC'd twins). The GC line has since been completed on both sides:SettledAtis discharged, not assumed (EvidenceDischarge.lean:settledAt_of_allHeard_honestderives it from honest reachability plus the all-heads frontier, the causal-stability argument, with the frontier-maintenance lemmas axiom-free andcreateReplicathe one breaker, i.e. exactly the open-membership gate); the commit GC is strengthened to bounded state (GC_BoundedState.lean:gc_safety_boundedvia the clock-swap drops the DAG skeleton entirely so the store costs O(live keep-set), with the compaction-era lineage collision handled by theClockCoherentpayload-is-a-function-of-the-clock guard and machine-checked at its resurrection boundary); and the run-table representation is now a shipped serializer (serialize.js, reconciled bit-for-bit with the mechanized accounting), which closes the absolute-chain save-size gap: real save sizes 24 KB / 22 KB / 73 KB / 120 KB on the four traces (from 35 MB / 53 MB / 170 MB / 243 MB as-shipped JSON), on par with the smallest production save and never growing on delete. And the sync layer is now real: an Automerge-repo-style delta gossip protocol (sync.js: peers exchange head frontiers, ship only the missing commits, ingest re-computes each state and gates on the content-id so state is never trusted over the wire; measured payload ~0.28–0.38× a whole-state resync) and a certified stability GC (frontier.js: the per-replica frontier is the runtime realization ofAllHeardSince's evidence commits,stableCutis their meet, andcompactStablecompacts only at a cut whose certificate is present — refusing otherwise, the executable form ofsettledAt_of_allHeard; the directed discriminating-remove test shows it refuse while a replica is unheard-from and fire soundly once heard, reads identical to a never-compacted control throughout, with the old asserted compaction diverging as the FAIL companion). 57 runtime tests. -
docs/porting-op-based-crdts.md— recipe for porting a new op-based CRDT into Sal's state-based signature. -
ROADMAP.md— open research threads (Neem soundness metatheory, op→state transfer, the tombstone-free/prefix-free RGA results) with status and entry points. -
docs/metatheory-note/joinpeel-note.pdf— a self-contained paper-style note: why the original VCs are inadequate (worked counterexamples), the set-relative repair and the Join Lemma, the newJoinPeelVCs, and the mechanization. -
Sal/ConditionedMRDTs/sal-mrdts.pdf— the consolidated paper-style note (one document, three parts, replacing the former separate metatheory, embedded-chain design, and sequential-specification notes). Part I, the MRDT (ternary-merge) metatheory: what an MRDT is and how to describe one (with the counter and the OR-set as worked examples), the corrected flat metatheory (the eight VCs with intuition, the delta contract and why no lattice contract can exist, the causal-delta equation, the LCA lemma erratum, the defeater execution, the discharged production catalogue — with TikZ execution diagrams), the conditioned metatheorem, and the factored discharge route (HonestReach× per-configurationJoinLemma3At, the mergeable queue as its flagship). Part II, the embedded-chain RGA design note: birth-chain sort keys, the entropy-coded coordinate representation and the entropy law, the insert prefix, the validation battery, the compaction theorem, the sided generalization with the Fugue/FugueMax arc, and the Eg-walker comparison. Part III, Convergence Is Not Correctness, the sequential-specification campaign: the specification gap RA-linearizability leaves open, the four tiers and their invariant taxonomy (identity hygiene → geometry → composition), the three machine-checked refutations and the two-axis do/merge separation (every placement a named kernel theorem), the composition caveat with the dead-anchor corner and the open question oq:seqwitness, and the consolidated verified matrix absorbing task #64's in-repo rows. Now 83 pages: Part I additionally carries the runtime-facing metatheory (virtual LCAs with the exact covering proposition and the machine-refuted single-MCA shortcut; commit GC withgc_safetyand the keep-set; the stability VC withSettledAt, the discriminating-remove countermodel, andstability_simulation), and Part II additionally carries the closed maximal-non-interleaving arc (full adapted W-K Theorem 9 with the corrected backward exception and the Table-1 placement), the chain-price section (the sibling-splice fooling pair, the retention characterization, the 2×2), and the storage layer (re-coding,compactEliasDelta, spine fusion, the run-table representation, all four measurement tables with their accounting models, and the cross-system benchmark with the grows-on-delete churn table). Plus one consolidated open-questions list and one mechanization map. -
Sal/ConditionedMRDTs/defeater-walkthrough.pdf— a slow, self-contained walkthrough of the defeater execution for the published (pre-correction) MRDT soundness proof: the paper's induction and eight-law toolbox restated, every version's state and LCA checked, then the critical merge exhausted move by move (each of the five merge rules in both orientations, the automation catalogue, and the peel-architecture repairs), every failure anchored to a computation or a named kernel theorem (no_inter_lca_2op_rem_peel_of_defeater,crack1_witness,reunification_peel_obstruction,no_proper_back_block,killTest_no_common_U); states precisely that the theorem survives while the proof does not, and re-runs the same merge through the corrected delta-contract route in five lines. Expandssal-mrdts.pdfPart I §4.2. -
Sal/CRDTs/Metatheory/— the Neem soundness meta-theorem for binary-merge CRDTs, corrected: machine-checked counter-models refute the paper's merge-case proof and show the 24-VC bundle insufficient (a reachable non-RA-linearizable execution underCoreVCs+ full semilattice laws); the repaired chainsCoreVCs + JoinPeelVCs ⇒ RA-linand the CD ladderCoreVCs + ACI + inflation + CD ⇒ RA-linare proved end-to-end (0 sorries), with CD proved the exact minimal residual. See itsREADME.mdandFINDINGS.md(A1–A9, drafts A10–A12). -
Sal/ConditionedMRDTs/— the ternary (three-way merge) metatheorem over the version DAG: the LCA lemma as a reachability invariant, a validated VC set (CoreVCs3CD + FeasibleDeltaVCs3 + CDVC3), and kernel-checked end-to-end RA-linearizability for all 12 production MRDTs through one generic conditioned framework: the eleven flat datatypes (OR-Set, OR-Set-efficient, Enable-wins flag, Grow-Only Set and Map, Increment-Only and PN counters, tombstone RGA, Peritext, Multi-Valued Register, Add-Wins Priority Queue) at the identity instantiation with their VC discharges underMRDT_Instances/(one directory per RDT), and the rehoming tombstone-free RGA — provably outside the VC schema — at full generality (MRDT_Instances/RGA_Rehoming/RA_Lin.lean): RA-linearizability up to observational≈at every reachable configuration, from a single honest-delivery assumption (born accuracy + applicable delivery), kernel-clean. (Demoted 2026-07-16: the convergence capstone stands, but the design is sequential-spec-refuted at thedolevel —rehoming_seq_refuted,MRDT_Instances/RGA_Rehoming/RGA_SeqSpec_Refuted.lean: a single-replica delete reorders survivors, so the datatype does not implement the naive text buffer — and fused Peritext, its pure instantiation, inherits the residual at the render (fused_delete_reformats_survivor: deleting a plain character re-formats an untouched survivor). It is retained as the framework's only fully general instantiation and as the delete-order countermodel; the canonical sequence RDT is the embedded-chain family below, and the canonical fused Peritext is now the embed-basedPeritext_Embed/.) Beyond the production mirrors, five born-conditioned instances: the bounded (escrow) counter — convergence is flat, and the boundvalue ≥ 0is a kernel-checked safety theorem at every version of every reachable configuration whose history satisfies the client applicability contract (bc_version_inv,MRDT_Instances/BoundedCounter/); and the mergeable queue of Peepul (PLDI'22 Certified Mergeable Replicated Data Types) — concurrent enqueues form a non-commuting clique, so norcassignment exists and the flat VC engine is structurally unavailable; its Join Lemma is instead proved directly, exhibiting Peepul's three-way merge as the linearization witness at every merge, giving per-version RA-linearizability under honest delivery (queue_ra_linearizable3,MRDT_Instances/MergeableQueue/), with the dequeueapplicablehead-check discharging honesty (qHonest_of_applicable); and the FWW reservation register — first-writer-wins with the arbitration timestamp in the payload (a min-semilattice, the positive complement to thelww_merge_needs_timestampskill-test), whose winner is characterized at every reachable version (fww_version_min, honesty-free) and whose claim-when-unset discipline is deliberately consumed by no theorem: "unset" is not stable under concurrent honest extension, so a merge-based register is a reservation, never a mutex; the LWW register — the max-semilattice dual, with-metadata arbitration carried in the payload so its eight VCs are puremax-algebra and its winnerlww_version_maxis characterized at every reachable version (honesty-free,MRDT_Instances/LWWRegister/), the resolution of thelww_merge_needs_timestampskill-test in the LWW rather than FWW direction; and BudgetCart — a budgeted shopping cart (OR-set contents with add-winsrc, per-replica spend derived from live instances so removal refunds the adder automatically), convergent through the OR-set route (BCart_ra_linearizable3_eq) with its budget-safety theorem delivered hypothesis-gated (bcart_version_inv_gated): the ungated obligation is provably false because vis-only causal folds are enumeration-dependent under concurrent add/remove — the instance that forces Open Question 8 (rc-oriented causal witnesses). The composition kit (Sal/ConditionedMRDTs/Metatheory/Product*.lean) turns the binary heterogeneous product of conditioned MRDTs into once-only theorems — convergence (concatenation join witness), safety (one-sided causal witnesses; the two-sided form is provably impossible), and the ≈-quotient lift — and its first real consumer is composed Peritext (MRDT_Instances/Peritext_Composed/): rich text as RGA ⊗ marks (peritextComposed_ra_linearizable_up_to_eq, up to ≈_RGA × =; marks resolved at read time by the RGA's own path-climbing, render ≈-congruence kernel-checked), against a from-scratch alternative assessed structurally infeasible. The fused Peritext is the tombstone-free-and-live alternative: characters and boundary marks share one RGA (PeritextElt = char ⊕ boundary), so mark endpoints ride document order directly rather than freezing tree paths, with independent positional intent theorems (render_id_active_iff_between,render_span_before) at the cost of non-atomic mark placement (the mark-positioning trilemma — atomic / tombstone-free / live, pick two). It exists twice, deliberately:MRDT_Instances/Peritext_Rehoming/(on the rehoming kernel,peritext_ra_linearizable_up_to_eq) inherits the rehoming delete-reorder residual at the render (fused_delete_reformats_survivor, machine-checked: deleting a plain character re-formats an untouched survivor) and is retained as the countermodel; the canonical fused Peritext isMRDT_Instances/Peritext_Embed/(on the embed kernel,peritextEmbed_ra_linearizable3— a pure instantiation of the now payload-generic embed instance), where the state is the document, the read is amapwith no fuel or well-formedness hypotheses, and the residual is fixed as a general theorem:renderIds_del(kernel-clean on {propext, Quot.sound}) proves deleting a character leaves every other character's rendered formatting bitwise untouched, with the rehoming witness trace replayed clean in the SPOT block. On top of it, the document-order mark read model (Peritext_Embed/PeritextEmbed_MarkIntent.lean) gives the paper-faithful semantics the earlier no-leak claim got wrong: a deleted boundary anchor rehomes to the nearest surviving neighbour in reading order (gravity perstartSide/endSide, growth end-side only), anddoc_no_backward_leak(kernel-clean on[propext]alone) proves a rehome never migrates a span backward — the positive that replaces the retractedmark_*_no_leak, with the tree-ancestry leak machine-refuted as its companion, the Litt Ex 1-8 renderings pinned (bold expands at its end, a link does not), and the trilemma's atomicity cost stated honestly as a theorem (doc_delete_can_respan) rather than hidden. The sequential-spec campaign (MRDT_Instances/SeqSpec_Flat.lean,MergeableQueue/MergeableQueue_SeqSpec.lean,EmbedRGA/EmbedRGA_SeqSpec.lean) supplies the independent specification RA-linearizability deliberately does not: RA-lin certifies convergence to the datatype's own fold, so a single-replicadobug is invisible to it; these theorems prove, per RDT, that the fold of any single-replica history equals a straightforward sequential program, via an explicit inductive invariant. Tier 1: the eleven flat RDTs (view homomorphisms; MVR and AWPQ need genuine invariants — overwritten tags stay staked, stake tags stay nodup). Tier 2: the mergeable queue = a plain functional FIFO. Tier 3: the embed RGA = the naive insert-at-index text buffer (the geometric adjacency lemmachainBefore_snoc_iff), with the published tombstoned RGA inheriting the same buffer spec as a corollary (EmbedRGA_SeqSpec_RGA.lean, standalone target). Tier 4, completing the campaign's positive tiers: the embed-based fused Peritext = the naive marked-text editor (peritextEmbed_seq_sound,Peritext_Embed/PeritextEmbed_SeqSpec.lean) — the render is the editor's screen on every sequentially honest history, by composing the now payload-generic tier-3 buffer soundness with the shared pure render walk; the negative rows are the rehoming RGA (rehoming_seq_refuted, do-level) and, at the render, the rehoming-based fused Peritext. Superseded routes, impossibility results, and plans live underDevelopment/. -
Shesha (
Sal/ConditionedMRDTs/MRDT_Instances/Shesha/) — a tombstone-free sibling-linked replicated list (order lives in links between live nodes; delete splices and retains nothing), designed live on the whiteboard (2026-07) and named for Ananta-Shesha, "the remainder". Phase-1 verification:sequential_soundness(single-replica folds = the naive linked list; kernel-clean) anddelete_preserves_survivor_order— the property the flat tombstone-free RGA provably violates — plus machine-checked litmus witnesses byte-matched to the Python reference, merge symmetry (merge_comm) proved at state equality, and the two fooling-pair impossibility theorems (I1/I2_no_merge_function: no tombstone-free merge can match the tombstoned oracle, nor the strong list spec) quantified over all merge functions. Phase-2b merge lemmas (Shesha_Forest/Skel/M0/M2.lean: a parent-chain/depth layer, the exact skeleton characterization, a placed-exactly-once accounting, and thewpar↔tree-structure bridge): Lemmas M0 and M2 fully closed, all six files sorry-free and kernel-clean —merge_WF(merge_read_nodup: every id placed at most once, via a generic DFS-count engine over splice-chain determinism), the survivor-set identitymerge_ids(the merge displays exactly the merge-live ids: ⊆ by working-set + marker-freeness, ⊇ by placement + the positive marker climb + a level-graded emission chain), and the order theoremmerge_extends_L/merge_L_filter(merge-surviving L-pairs keep exactly L's display order: a skeleton row is structurally the shallow-W front of its node's child forest, marker expansion turns it into the shallow-survivor front, and the collapsed DFS reads out the survivor filter ofread L— the merge-time splice IS the delete splice). Phase-2c (Shesha_Evolution/Cond.lean): the honest-evolution layer is closed — branches evolved from the LCA by honest steps (fresh nonzero ids, live anchors/targets) preserveWFand the branch-structure invariantLRowsOK, so with cross-branch Lamport uniqueness as the sole global contract, every honestly-reached merge is well-formed, symmetric, displays exactly the merge-live ids, and extends the LCA order (merge_*_honest, kernel-clean). Shesha is wired into the one framework as a conditioned instance (SheshaD, timestamp-as-id) by the mergeable-queue route — with a twist the framework had never met: the queue-style plain join hook is provably FALSE for Shesha (Shesha_Join_Refuted.lean, machine-checked: canonical states are existential and, for Shesha, not unique per event set — a concurrent(ins x←a, del a)pair folds to different live sets under its two enumeration orders — soJoinLemma3Atcan be fed a misaligned canonical triple that makes the merge emit a node twice; the queue was immune only because its canonical states are unique). The corrected route is new generic metatheory (Metatheory/WitnessClass.lean, kernel-clean): join lemmas relative to a witness class, instantiated for Shesha at effective enumerations (SheshaEff: every insert applies — the class real executions produce, under which the live set is determined by the event set alone). The capstoneshesha_ra_linearizable3keeps its exact statement; the join hookshesha_join_at_effis now proved (phase 2e) by a closed two-way reduction: analysis — every effective witness's fold is the delete-collapse (dropF) of its anchored forest (Shesha_EffFold.lean: delete postponement, order-free set-drop, head-insertion rows, collapse rows = fronts;Shesha_Hook_Facts.lean: Lamport clocks make causal pasts finite and enumerable, so honesty always bites — the exclusion lemmas — andwitness_nfputs every join slot in normal form) — and assembly — any vis-compatible anchored forest for the union realizes its collapse as aSheshaEff-canonical state (Shesha_Witness.lean:presplice_canonical, planning the forest then deleting ascending;plan_pwdischargesrespects loOnstructurally); the replay layers (positive op commutations, graft algebra, insert-phase realizationplanF) feed both halves fromShesha_Replay.lean. The last owedsorrywas the merge-correctness coreshesha_rows_residue(the ternary merge output is the collapse of a pre-splice anchored forest of the union) — and it is now machine-checked FALSE (Shesha_Rows_Refuted.lean, 2026-07): at an honestSCoh-aligned config (SCohvacuous) the merge of the canonical folds ofLCA=[ins 1],A=[ins 2←1, ins 4←⌂, del 1],B=[ins 3←1]is[3,4,2], splitting deleted node1's children{2,3}around the concurrent root sibling4; no pre-splice forest collapses to it, and[3,4,2]is not the fold of anyloOn-respecting linearization of the union — soshesha_ra_linearizable3(which typechecks from thatsorry) rests on a now-known-false lemma and its statement is itself unsatisfiable at this reachable merge. The split is caused by Shesha's local-order-preserving splice over a mutable forest — not by anchor-forgetting: the RA-linearizableRGA_Tombstone_Freealso forgets the anchor on delete, but it re-homes and re-sorts survivors by their global key, so its read is always a fold (⇒ RA-lin) at the price of reordering survivors (tombstone_free_violates_delete_order); Shesha instead keeps local sibling order (delete_preserves_survivor_order), so one replica is delete-order-faithful but the merge of two mutable forests is not a global fold. This is the sequence-CRDT trilemma (local-order-preserving delete ⊻ merge RA-linearizability). The dissolution is not anchor-retention but immutable stored positions (KC+KartikDevelopment/RGA_OrderPreserving_Reference.lean, task #63): freeze each node's ancestry path at insert, read = lex-sort by frozen position, delete = pure drop — positions never move, so delete-order holds and the read is a fold; on this trace2,3keep contiguous frozen paths[k₁,k₂],[k₁,k₃]while4is[k₄], so4cannot split them and[3,4,2]never arises (the trilemma reasserts only at the insert-after-already-deleted-anchor corner: the frozen path then needs the dead anchor's position — an append-only position map, i.e. a metadata tombstone, or default-to-root that loses order). The owed research decision is either the immutable-position re-encoding or a capstone restatement to Shesha's actual guarantee (convergence + licensed divergence), which the PBT harness verifies, not a proof of the current statement. Also ahead: Theorem P (causal pairwise display stability) and Theorem D (licensed divergence vs the tombstoned RGA). Design record, pen-and-paper proofs, PBT harness (~16k merges, 0 displayed-pair flips) and the verified anomaly-comparison matrix (6 implementations + yjs/automerge/loro/list-positions) underwhiteboard/. -
Sal/MRDTs/RGA_Rehoming/doc/why-the-path-matters.pdf— a visual (TikZ) account of why the tombstone-free RGA needs the operation path, and why a prefix-free variant cannot be VC-verified. -
whiteboard/— the Shesha exploration record: Excalidraw boards (design trail, fooling pair), self-contained design + proof notes, the PBT harness, the verified anomaly matrix (anomaly-matrix/anomaly_matrix_report.md), and the related-work verification. After the rose-tree Shesha's merge was machine-checked non-RA-linearizable (Shesha_Rows_Refuted), the successor sibling-edge design (sibling-edge-design.pdf) extends the tombstone-free RGA with a second immutable origin (a right sibling edge) and carried spine paths, delete = pure remove (no rehome): a brute-force model (sibling-origin-pbt.py) finds it convergent and RA-linearizable — aloOn-fold for every one of ~37,000 random merges, single- and multi-epoch, 0 anomalies — while preserving single-replica delete-order and non-interleaving. The design search then ran through the consolidated litmus suite (whiteboard/litmus/: tests L1–L25 with provenance + a randomized version-DAG PBT harness, 16 designs), the delta tree (KC's parent-relative-ranges design — refuted as strictly dead-free by two named mechanisms, then corrected by identity arbitration;delta-tree-design.pdf), and the retention question (retention-countermodel.pdf: what must be remembered about a deleted character — answer: nothing beyond the coordinates of the living, if the carve is timestamp-faithful), and its endpoint is the embedded-chain RGA (design note now Part II ofSal/ConditionedMRDTs/sal-mrdts.pdf): coordinates = birth chains under an order-preserving prefix-free delta code, ties impossible, the merge never decides an order — battery-clean (except one-sided L19, RGA's own anomaly), DAG-PBT-clean at 420 executions, lockstep read-equal with the published tombstoned RGA 120/120, and entropy-optimal (~4 bits/level sequential; IEEE 754 as carrier machine-refuted). Its Lean mechanization has landed its capstone:embed_ra_linearizable3(Sal/ConditionedMRDTs/MRDT_Instances/EmbedRGA/) — RA-linearizability per version at every honestly reachable configuration, kernel-clean, parametric in the code (the unary code, the binary delta code, and the flipped Elias-δ codeeliasDeltaCode—log δ + O(log log δ)per level,Embed_Code_EliasDelta.lean— are all provedOrderedPrefixCodeinstances: three encodings on one proof, the δ-flip capstone inherited with zero new content asembed_ra_linearizable3_eliasDelta), via the mergeable-queue route with the join discharged by canonicity (e_fold_canon: well-formed enumerations of one event set fold to the same state) — in nine sections where the rehoming-based tombstone-free RGA needed its 55-file conditioned chain, closing withapplicable⟹honesty (eHonest_of_applicable) and the instance intent theorems (delete-order preservation as sublist stability). Beneath it,Sal/MRDTs/RGA_Embed/carries the map-model kernel (commutations to state equality underrc = Either; coherence + chainState closures; display stability — step stability axiom-free — the chain-lex theorem, unique decodability, subtree-convexity non-interleaving, andnative_decideSPOTs where the flat RGA's delete-reorder witness gets the opposite verdict). The entropy claims are calibrated on real editing traces (whiteboard/litmus/entropy_measure.pyon josephg/editing-traces, endContent-verified: order metadata ≈ 1.4–1.8 bits/level; context-conditioned coding measured NOT worth mechanizing; run coalescing the real lever —whiteboard/order-coding-compression-notes.md). And the compaction theorem has landed (rga_read_eq_embed_read,EmbedRGA_ReadEquiv.lean, kernel-clean, standalone build target): on every honest event set, any enumeration of the published tombstoned RGA's visible ids in its own relationalvisible_ltorder — proved total and asymmetric on the birth tree en route, facts the published side never had — equals the embed read, element for element; the lockstep 120/120 is this theorem's tested form, and the embedded-chain RGA is now, as a theorem, the published RGA with the tombstone set compressed into the coordinates. The coordinates themselves are now GC-able, as a theorem (EmbedRGA_Recoding.lean): an order-preserving re-coding below a stable cut, in the lazy-translation formulation (a stable-prefix map applied at rest and on ingest), commutes with the fold (eRecode_applySeq) and leaves every read identical (eRecode_reads_identical), with canonicity and the capstone's per-version witness transporting (eRecode_ra_transport), all kernel-clean; a first-class negative (eRecode_ext_global_collapse) shows the whole-history formulation trivializes (extension-commuting at every historical mint forces the re-map to a constant prefix), so lazy translation is the only nontrivial shape. Measured (embed_recode_check.py): 200 bits to 1 bit on a delete-heavy 200-chain, 500/500 randomized states including concurrent cross-cut continuations, and the deliberately order-breaking control flips reads, pinning the order hypothesis as load-bearing (design noteembed-recoding-note.md; deferred there: the protocol half of choosing a common cut, and re-basing honesty so the capstone runs natively in the new epoch). The compaction stack is now verified with no remaining formal debt: the honesty-rebasing obligation(⋆)— the single residue shared by the single-epochAnchorsFactorBeyondgap and the multi-epochCompatChain— is discharged (EmbedRGA_HonestyRebase.lean, kernel-clean, Python-validated first with no countermodel): a re-coded configuration is honest modulo the coordinate order-embedding via the invariantI(coded anchored forest over live coordinates), whichEHonestestablishes once and everyStablePrefixMappreserves, so compaction reads are native rather than by-transport at every epoch. The concrete compaction is verified end to end (compactEliasDelta_settled_reads,EmbedRGA_CompactEliasDelta.lean, kernel-clean): at a settled cut of a disciplined honest configuration, drop-dead-ranges plus rank-renumbering under the flipped Elias-δ code preserves every read of every beyond-cut continuation under the lazy translation, with the in-flight wrinkle pinned both ways in the SPOTs (dense renumbering under an in-flight sibling provably flips a read; the guarded pass skips the group and still compresses). TheAnchorsFactorBeyondresidue is discharged through the generation discipline (EmbedRGA_AnchorsFactor.lean), with a recorded countermodel showing bare honest reachability cannot supply it. The runtime ships the same algorithm plus spine fusion (compact.js, 42 tests), measured on real editing traces at 1.7×–3.2× end to end with history-independence holding three ways; the per-level attribution shows fusion removes essentially all dead levels and the remaining cost is live-tree shape (mean live depth 835–1468 levels), making live-run re-coding (task #73's isometric-fold layer) the next order-of-magnitude lever — and that lever is now verified too (RunTable.lean+EmbedRGA_RunTable.lean): the tail-attachment lemma (tail_attachment, at {propext, Quot.sound} alone), the representation iso in both directions (stateOf_tableOflosslessness +tableOf_stateOfcanonicity — over label chains and liveness, deliberately not timestamps, which would be false after an epoch), the two-case contracted comparator equal tokeyLtfor every code (cmpTable_eq_keyLt), the walk-is-the-display theorem,tableOf_congr(the table is a function of the live-chain set, so merges rebuild identically in any delivery order),tableOf_insert_extend(typing bumps one length field: O(1) per keystroke, as a theorem), and the epoch compositionrunTable_epoch— the only theorem in the run-table stack carrying a settled-cut hypothesis, its absence elsewhere being the formal content of the measured no-stability-gate finding; SPOTs pin coalesce-necessity and the no-split rival's wrong display as FAIL companions. Generic simulation lemmas for split/delete/materialization remain owed (SPOT-pinned meanwhile), as does the sided run table. The successor arc is the sided embed (sided-embed-design-note.md): two-sidedness as a parameter, not a second datatype. An insert names an anchor and a side; the display rule generalizes from the prefix rule to the in-order rule, made plain lexicographic again by a marker alphabet (R band < marker < L band, the L band in the complemented code); the current datatype is the all-R fragment, exactly; and side selection (always-R gives RGA, Fugue's between-rule gives non-interleaving) is a generation policy, not a datatype choice. The Python model and full battery (litmus/embed_sided.py) validated every design-note prediction on the first run: under the Fugue policy L19 flips clean (backward runs become L-chains) with the rest of the gauntlet staying clean, the all-R fragment is lockstep-exact with the one-sided embed, and the side-bit + per-band-code carrier is faithful. The Lean port has landed both layers, kernel-clean: the sided chain-lex kernel (Sided_ChainLex.lean: the sided marker theoremsdisplay_iff_schainBefore, axiom-free totality, unique decodabilitysidedCoordOf_inj, the all-R fragment theoremschainBefore_liftR, and in-order-interval subtree convexityschain_subtree_convex, the Fugue intent target), and the conditioned instance with its capstonesided_embed_ra_linearizable3(MRDT_Instances/SidedRGA/) — RA-linearizability at every honestly reachable configuration for every side assignment, sides being payload to convergence. The per-policy intent theorems have landed (SidedRGA_Intent.lean, kernel-clean):sFold_liftOpproves the always-R sided instance IS the one-sided instance fold for fold, unconditionally (a pure simulation — the sort keys coincide definitionally, so every one-sided theorem transports); andsided_fold_subtree_convexproves subtrees display as contiguous blocks in any chain-generated fold, so any run that chains — the Fugue policy's shape for forward and backward typing alike — is never interleaved by concurrent survivors, with the L19 trace replayed contiguous through the Lean fold as its SPOT. And the Fugue policy itself is now formal (SidedRGA_Fugue.lean, with the design notewhiteboard/fugue-maximal-noninterleaving.mdand the Python validatorlitmus/fugue_noninterleave_check.py): an intent-op layer (insert at position), the Fugue side rule as a generation-time function of the replica-local grow-only tree (dead nodes included), and the Weidner–Kleppmann maximal-non-interleaving Definition 4 adapted and formalized over reachable configurations. The verdict is a machine-checked separation, exactly the paper's own Fugue-vs-FugueMax gap landing on our policy: run-contiguity is proved kernel-clean (fugue_reachable_runs_no_interleave, via subtree convexity — concurrent runs never interleave, forward or backward), forward non-interleaving is stated and Python-clean over 1500 randomized states (proof needs the display-to-traversal theory, gap G2), and the FULL maximal-non-interleaving property is refuted twice on reachable traces (fugue_not_maximally_noninterleaving: the kernel's newest-first tiebreak reverses the paper's lowest-ID-first;fugue_not_maximally_noninterleaving_backward: the paper's Figure-7 execution, condition (2)) — as it must be, since W-K themselves prove plain Fugue is not maximally non-interleaving and our policy is Fugue with the RGA recency tiebreak, not FugueMax. That residue has since landed in two waves. The FugueMax tiebreak is a third policy (SidedRGA_FugueMax.lean), realized in the kernel by right-origin tags (an order-reversing fixed-width tag ahead of the R band,SidedMax_ChainLex.lean): the condition the recency tiebreak refuted becomes a positive theorem (fuguemax_same_origin_low_first), and the sided sequential-spec tier is closed (the sentinel-rootedsided_seq_sound,SidedRGA_SeqSpec.lean). The traversal theory then landed (Sided_Traversal.lean+SidedRGA_NonInterleaving.lean, design record §9 of the Fugue note, Python-clean over 12 directed cases and 1800 randomized states inlitmus/traversal_check.py): FugueMax forward non-interleaving is discharged kernel-clean (fuguemax_forward_ni, via the chain-shape lemmaloShape_of_invand a first-after descent on the left-origin walk), and the backward condition is now discharged as well (SidedRGA_Backward.lean): the design phase machine-refuted the live-witness reading of the paper's Lemma-5 exception (Figure 7 plus one delete needs the tombstone itself as the witness, so the corrected statement quantifies the witness over minted records, exactly as the paper's own text does), and the mechanization discharges the corrected condition via theRBkmint-time clause bundle and a deterministic four-route witness construction, closingfuguemax_maximally_noninterleaving: the full adapted Weidner-Kleppmann Theorem 9, kernel-clean, to our knowledge the first mechanized maximal non-interleaving result. The plain Fugue policy's forward condition is discharged in W-K's own vocabulary too (fugue_forward_ni,SidedRGA_Fugue_ForwardNI.lean, kernel-clean; the link layer rebuilt as an external invariant over an untouchedFugueReach, with ~85% of the FugueMax machinery transferring verbatim). The FugueMax variant also carries its own convergence capstone (fuguemax_ra_linearizable3,SidedRGA_FugueMax_RA_Lin.lean, kernel-clean: RA-linearizability at every honestly reachable configuration of the tagged datatype, parametric in the delta code, via fold canonicitym_fold_canon), with one substantive finding: unique decodability of the tagged coordinates needs tag wellformedness (TagsOK), so the FM honesty contract carries a clause the plain sided contract did not need — the right-origin tag is convergence-load-bearing, not just intent-load-bearing. The remaining sided residue is the price question alone: what the right-origin tag costs in coordinate entropy (task #89).
Pranav Ramesh, Vimala Soundarapandian, KC Sivaramakrishnan. Sal: Multi-modal Verification of Replicated Data Types.
The paper evaluates Sal on 13 RDTs (4 CRDTs + 9 MRDTs), 312 VCs total (24 per RDT). The breakdown across the three stages (DG = dsimp + grind; LB = lean-blaster; ITP = Aristotle-assisted interactive proof):
- 215 VCs (68.9%) via DG — TCB not enlarged.
- 87 VCs (27.9%) via LB — TCB enlarged to include Z3.
- 9 VCs (3.0%) via ITP, all closed using Aristotle, whose outputs are kernel-checked — TCB not enlarged.
| RDT | DG | LB | ITP |
|---|---|---|---|
| Increment-only counter MRDT | 24 | 0 | 0 |
| PN-counter MRDT | 24 | 0 | 0 |
| OR-set MRDT | 3 | 21 | 0 |
| Enable-Wins Flag MRDT | 9 | 14 | 0 |
| Efficient OR-Set MRDT | 2 | 22 | 0 |
| Grows-only set MRDT | 24 | 0 | 0 |
| Grows-only map MRDT | 22 | 0 | 2 |
| Replicated Growable Array MRDT | 15 | 9 | 0 |
| Multi-valued Register MRDT | 24 | 0 | 0 |
| Increment-only counter CRDT | 24 | 0 | 0 |
| PN-counter CRDT | 16 | 2 | 6 |
| Multi-Valued Register CRDT | 24 | 0 | 0 |
| OR-set CRDT | 4 | 19 | 1 |
Two patterns from the paper: MRDTs generally need less SMT than CRDTs because three-way merges express causality directly, and map-based reasoning stresses current Lean automation more than set-based reasoning (the 8 remaining ITP goals are concentrated in map-heavy RDTs).
Since publication the suite has grown from 13 to 29 RDTs, and most of the added CRDTs were proved with the uniform kernel-verifiable pattern described under The sal tactic, without invoking Blaster for the majority of VCs. A refreshed DG/LB/ITP breakdown across all 29 RDTs is future work. The papoc2026 branch snapshots the repo at the paper-artifact state.
MIT; see LICENSE.