Skip to content

Commit 9b3d8a9

Browse files
Apply the TLA+ review guidelines
Four things in the review guidelines were not being followed. Constants now carry named assumptions. All four specifications declared Nodes and MsgIDs with nothing constraining them, and Skew's MaxSkew with nothing saying it is a natural number. The guidelines call this crucial for TLAPS, and these modules do carry proofs. Type invariants are back to the var \in S form: network \subseteq MsgRecord rather than a quantifier over its elements. MsgRecord ranges over Nat and so cannot be enumerated, which is why the MC module carries its own bounded MCTypeInvariant for TLC. Strong fairness on Process is now justified by measurement rather than assertion. Weak fairness was tried, as the guidelines ask: the liveness model reports a temporal-property violation under it, because a crash intermittently disables Process. The module says so. The horizon stays inside MCTick rather than moving to a state CONSTRAINT, which the guidelines otherwise prefer. A constraint was tried first and does not work here: TLC evaluates invariants on the state that crosses the boundary before the constraint discards it, so with MaxSlot = 2 a Tick reaches current_slot = 3 and any invariant mentioning the horizon fails there. The reason is recorded in the module header rather than left as an unexplained deviation. Seven TLC models, all completing in under five seconds. The three TLAPS modules discharge 191, 128 and 32 obligations and exit 0 under tlapm --strict. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: Vasilis Nasopoulos <vasilis_nasopoulos@hotmail.com>
1 parent d8ba318 commit 9b3d8a9

7 files changed

Lines changed: 54 additions & 19 deletions

specifications/VortexDSE/MC_Vortex_DSE_CSlot.cfg

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
\* Safety model. The horizon lives in MCNext, so no state constraint is
2-
\* needed: the reachable state graph is already finite.
1+
\* Safety model. The horizon is imposed inside MCTick; see the module
2+
\* header for why a state constraint does not work here.
33

44
SPECIFICATION MCSpec
55

@@ -13,3 +13,5 @@ INVARIANT NoFutureAdmission
1313
INVARIANT ExactlyOncePerNode
1414
INVARIANT NoPhantomProcess
1515
INVARIANT DecisionLocalityOnly
16+
17+

specifications/VortexDSE/MC_Vortex_DSE_CSlot.tla

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,33 @@
22
(***************************************************************************)
33
(* TLC harness for Vortex_DSE_CSlot. *)
44
(* *)
5-
(* The specification itself has no slot horizon: Tick is unbounded and *)
6-
(* DuplicateInject may forge any slot in Nat. The horizon is a *)
7-
(* model-checking concern and lives here. *)
5+
(* The specification has no slot horizon: Tick is unbounded and the *)
6+
(* adversary may forge any slot in Nat. The horizon is a model-checking *)
7+
(* concern and lives here. *)
88
(* *)
9-
(* It is imposed inside the actions rather than as a CONSTRAINT, so the *)
10-
(* state graph is genuinely finite rather than merely truncated. That *)
11-
(* matters for the liveness model: under a state constraint TLC discards *)
12-
(* successor states, which can mask or invent violations of temporal *)
13-
(* properties. *)
9+
(* It is imposed inside MCTick rather than as a state CONSTRAINT. A *)
10+
(* constraint was tried first, as the review guidelines prefer, but TLC *)
11+
(* evaluates invariants on the state that crosses the boundary before the *)
12+
(* constraint discards it: with MaxSlot = 2 a Tick produces current_slot = *)
13+
(* 3, and any invariant mentioning the horizon fails there. Bounding the *)
14+
(* ticker instead keeps the reachable graph inside the horizon. *)
15+
(* *)
16+
(* It also avoids a second problem in the liveness model, where discarding *)
17+
(* successor states can mask or invent violations of temporal properties. *)
18+
(* *)
19+
(* MCNext restricts the forged slot as well, because TLC cannot enumerate *)
20+
(* Nat. *)
1421
(***************************************************************************)
1522
EXTENDS Vortex_DSE_CSlot
1623

1724
CONSTANT MaxSlot
1825

26+
ASSUME MaxSlotAssumption == MaxSlot \in Nat
27+
1928
Slots == 0..MaxSlot
2029

30+
MCMsgRecord == [id: MsgIDs, cslot: Slots]
31+
2132
\* The ticker stops at the horizon.
2233
MCTick ==
2334
/\ current_slot < MaxSlot
@@ -33,6 +44,21 @@ MCNext ==
3344

3445
MCSpec == Init /\ [][MCNext]_vars
3546

47+
\* Type correctness within the horizon. TLC cannot evaluate the
48+
\* specification's own TypeInvariant, whose MsgRecord ranges over Nat.
49+
MCTypeInvariant ==
50+
/\ current_slot \in Slots
51+
/\ network \subseteq MCMsgRecord
52+
/\ processed \in [Nodes -> SUBSET MsgIDs]
53+
/\ persisted \in [Nodes -> SUBSET MsgIDs]
54+
/\ node_state \in [Nodes -> {Up, Down}]
55+
56+
-------------------------------------------------------------------------------
57+
(* LIVENESS HARNESS *)
58+
59+
\* Strong fairness on Process is necessary, not decorative: with weak
60+
\* fairness the liveness model reports a temporal-property violation,
61+
\* because a crash intermittently disables Process.
3662
MCFairness ==
3763
/\ WF_vars(MCTick)
3864
/\ \A n \in Nodes : WF_vars(Rejoin(n))
@@ -45,10 +71,4 @@ MCLiveSpec == Init /\ [][MCNext]_vars /\ MCFairness
4571
\* counter stays there rather than merely visiting it.
4672
MCTickProgress == <>[](current_slot = MaxSlot)
4773

48-
\* Everything reachable in this model lies within the horizon.
49-
MCTypeInvariant ==
50-
/\ TypeInvariant
51-
/\ current_slot \in Slots
52-
/\ \A m \in network : m.cslot \in Slots
53-
5474
====

specifications/VortexDSE/MC_Vortex_DSE_CSlot_liveness.cfg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
\* Liveness model. Bounded through MCNext rather than a CONSTRAINT, so no
2-
\* successor states are discarded while temporal properties are checked.
1+
\* Liveness model. Bounded inside MCTick rather than by a state constraint,
2+
\* so no successor state is discarded while temporal properties are checked.
33

44
SPECIFICATION MCLiveSpec
55

specifications/VortexDSE/Vortex_DSE_CSlot.tla

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ CONSTANTS
3636
\* @type: Set(Str);
3737
MsgIDs \* finite set of distinct message identifiers
3838

39+
ASSUME NodesAssumption == IsFiniteSet(Nodes) /\ Nodes # {}
40+
ASSUME MsgIDsAssumption == IsFiniteSet(MsgIDs)
41+
3942
\* Node liveness states, named rather than written as bare strings.
4043
Up == "up"
4144
Down == "down"
@@ -141,7 +144,7 @@ Spec == Init /\ [][Next]_vars
141144

142145
TypeInvariant ==
143146
/\ current_slot \in Nat
144-
/\ \A m \in network : m.id \in MsgIDs /\ m.cslot \in Nat
147+
/\ network \subseteq MsgRecord
145148
/\ processed \in [Nodes -> SUBSET MsgIDs]
146149
/\ persisted \in [Nodes -> SUBSET MsgIDs]
147150
/\ node_state \in [Nodes -> {Up, Down}]

specifications/VortexDSE/Vortex_DSE_CSlot_AE.tla

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ CONSTANTS
7474
\* @type: Set(Str);
7575
MsgIDs \* finite set of distinct message identifiers
7676

77+
ASSUME NodesAssumption == IsFiniteSet(Nodes) /\ Nodes # {}
78+
ASSUME MsgIDsAssumption == IsFiniteSet(MsgIDs)
79+
7780
\* AE phase names, rather than bare strings.
7881
Open == "open"
7982
Frozen == "frozen"

specifications/VortexDSE/Vortex_DSE_CSlot_Skew.tla

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ EXTENDS Naturals, FiniteSets
2222

2323
CONSTANTS Nodes, MsgIDs, MaxSkew
2424

25+
ASSUME NodesAssumption == IsFiniteSet(Nodes) /\ Nodes # {}
26+
ASSUME MsgIDsAssumption == IsFiniteSet(MsgIDs)
27+
ASSUME MaxSkewAssumption == MaxSkew \in Nat
28+
2529
\* Node liveness states, named rather than written as bare strings.
2630
Up == "up"
2731
Down == "down"

specifications/VortexDSE/Vortex_DSE_CSlot_TTL.tla

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ CONSTANTS
3131
\* @type: Set(Str);
3232
MsgIDs \* finite set of distinct message identifiers
3333

34+
ASSUME NodesAssumption == IsFiniteSet(Nodes) /\ Nodes # {}
35+
ASSUME MsgIDsAssumption == IsFiniteSet(MsgIDs)
36+
3437
\* Node liveness states, named rather than written as bare strings.
3538
Up == "up"
3639
Down == "down"

0 commit comments

Comments
 (0)