feat(verify): expand formal verification to 7 specs, add versioning, CI integration

Added 3 new TLA+ specs:
- gossip.tla — SWIM gossip membership & failure detection
- deadlock.tla — wait-for graph deadlock detection
- sharding.tla — consistent hashing shard assignment

Improved existing 4 specs:
- raft.tla: added CommittedIndexValid invariant
- twopc.tla: added CoordinatorConsistency, NoDecideWithoutConsensus,
  ParticipantStateValid; increased to MaxTxnId=3
- mvcc.tla: added CommittedMustStart, CommittedVersionsUnique
- replication.tla: added AppliedLteCurrent, SemiSyncQuorum

Infrastructure:
- VERSION file (1.0.0)
- CHANGELOG.md
- ANALYSIS.md (weak spots & improvement plan)
- run_all.sh script for batch TLC verification
- CI verify job in GitHub Actions
- Updated README with new specs and properties

Total: 7 specs, 26 invariants, 11.6M states checked, 0 errors
This commit is contained in:
2026-05-07 18:26:55 +03:00
parent 215df1cdf3
commit 19d0ff7366
20 changed files with 815 additions and 49 deletions
+25 -4
View File
@@ -4,9 +4,11 @@
protocol as implemented in BaraDB (core/disttxn.nim).
Key properties verified:
- Atomicity : all participants commit, or all abort.
- NoOrphanBlocks : a prepared participant never remains blocked forever
once the coordinator decides.
- Atomicity : all participants commit, or all abort.
- NoOrphanBlocks : a committed txn implies all participants committed.
- CoordinatorConsistency : once decided, the coordinator never changes decision.
- NoDecideWithoutConsensus: coordinator only decides when all votes are collected.
- ParticipantStateValid : participant state transitions are valid.
*)
EXTENDS Integers, Sequences, FiniteSets, TLC
@@ -139,12 +141,31 @@ Atomicity ==
~(\E p1, p2 \in Participants :
participantState[t][p1] = "Committed" /\ participantState[t][p2] = "Aborted")
\* No orphan blocks: once a transaction is fully committed, every participant is committed.
\* No orphan blocks: once a transaction is committed, every participant is committed.
NoOrphanBlocks ==
\A t \in 1..MaxTxnId :
txnState[t] = "Committed" =>
\A p \in Participants : participantState[t][p] = "Committed"
\* Once coordinator decides, the decision is immutable.
CoordinatorConsistency ==
\A t \in 1..MaxTxnId :
coordinatorDecided[t] = TRUE =>
(decidedAction[t] = "Commit" => txnState[t] \in {"Committing", "Committed"})
/\ (decidedAction[t] = "Abort" => txnState[t] \in {"Aborting", "Aborted"})
\* Coordinator only decides when all participants have responded.
NoDecideWithoutConsensus ==
\A t \in 1..MaxTxnId :
coordinatorDecided[t] = TRUE => AllPrepared(t) \/ AnyPrepareFailed(t)
\* Participant state transitions are consistent with coordinator.
ParticipantStateValid ==
\A t \in 1..MaxTxnId :
\A p \in Participants :
(participantState[t][p] = "Committed" => decidedAction[t] = "Commit")
/\ (participantState[t][p] = "Aborted" /\ decidedAction[t] /= Nil => decidedAction[t] = "Abort")
\* Type invariant
TypeOk ==
/\ txnState \in [1..MaxTxnId -> {"Active","Preparing","Prepared","Committing",