tla: export safety.rs with Verus's TLA+ exporter and compare it with Raft.tla - #28
Open
kiranandcode wants to merge 5 commits into
Open
kiranandcode wants to merge 5 commits into
kiranandcode wants to merge 5 commits into
Conversation
GState_tla.{tla,cfg,tla.json} are what `verus -V tla-export` writes for
src/raft/safety.rs with the twelve inv_* conjuncts named (export.sh
regenerates them byte for byte). RaftExportMC.tla fills only what the
export's report asks for: the three hole constants, the hosts Init leaves
to n, and Raft.tla's state constraint; the .cfg files are Raft.cfg's and
the deeper configurations' bounds. RaftExportCti.tla is Raft_cti.tla's seed
family in the export's representation, and cti.sh runs its per-conjunct
probes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Distinct states, diameter and verdicts match at Raft.cfg's and Raft_deep_lc.cfg's bounds; the same six conjuncts have CTIs from the same transitions. The remaining differences are traced to Raft.tla's (A3) action guards (deleting them reproduces the export's generated-state and CTI counts exactly) and its (A5) total-map reads (the export leaves an off-domain map read to stop TLC; restricted to in-domain acks, the inv_ack_persist probe gives 384 CTIs in both). The exporter bugs the comparison found are fixed in BasisResearch/verus#53. RaftExportCti.tla gains inv_ack_persist_dom and cti.sh probes it. The README points to EXPORT.md and gives the reads witness as 14 states: the shortest, as a one-worker run finds for both models (the 15 was a multi-worker trace). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ameter 24) The export's 16-worker run reported depth 25; one-worker runs of both models give 24, TLC's parallel depth being only an upper bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Running it: the witnesses run with one worker (four gave a 15-state reads witness); say that multi-worker depth is only an upper bound, and give the one-worker deep-reads run for the diameter. The same for README.md's oracle witness commands. - export/oracle.sh with Raft_noA3.cfg and Raft_deep_lc_noA3.cfg: the oracle CTI column, and the oracle without its (A3) guards, which has to be checked without TypeOK (its past-bound successors leave TypeOK's domains). - Raft_cti.tla: inv_ack_persist_dom, the oracle's side of the 384 row; both sides seed with CtiInit_ack_persist and check the restricted conjunct. - README.md: the CTI tables agree on which conjuncts and transitions, not on counts. - EXPORT.md: two of the three holes are not ghost payloads, a partial miss of the plan's acceptance criterion, and why no exporter could avoid it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step 4 of
plans/tla_export.md: run Verus's TLA+ exporter (-V tla-export) onsrc/raft/safety.rsand check the generated module with TLC against the hand-written oracletla/Raft.tla, at the same bounds. The comparison is written up intla/EXPORT.md. The exporter fixes it needed are in BasisResearch/verus#53.What is here
tla/export/GState_tla.{tla,cfg,tla.json}: the exporter's output, unedited.export.shregenerates it byte for byte.tla/export/RaftExportMC.tlaand.cfgs: fill only what the export's report asks for. That is the three hole constants (a command payload, the ghost ack mapq, andt_bump_term's new term),hosts(whichinitfixes only throughn), andRaft.tla's state constraint. There is one.cfgper oracle configuration (Raft.cfg,deep_lc,deep_reads, and both witnesses).tla/export/RaftExportCti.tla,.cfg,cti.sh:Raft_cti.tla's seed family in the export's representation, with the per-conjunct probe loop.tla/export/oracle.sh,Raft_noA3.cfg,Raft_deep_lc_noA3.cfg: the oracle columns.oracle.sh a3runs the same probe loop onRaft_cti.tla.oracle.sh noa3deletes the four (A3) guard lines in a temporary copy ofRaft.tla, then runsRaft.cfgandRaft_deep_lc.cfgwithoutTypeOK(which the guard-free past-bound successors violate), followed by the probe loop.tla/Raft_cti.tla:inv_ack_persist_dom, the oracle's side of the restrictedinv_ack_persistprobe.tla/EXPORT.md: the comparison.README.mdnow points to it, and gives the reads witness as 14 states (the shortest, as a one-worker run finds for both models).Results
Raft.tlaRaft.cfg: distinct / diameter / conjuncts violatedRaft_deep_lc.cfgRaft_deep_reads.cfgNoLC/NoR2Every difference is accounted for in
EXPORT.md:Set::rangewas refused; message-field quantifiers and step fields were holes; the guarding disjunction int_recv_appendstopped TLC.inv_msgs/inv_ltermsCTIs. Deleting the guards from a copy of the oracle reproduces every one of those numbers exactly.inv_ack_persistprobe stops at an off-domainleader_log[t], where the oracle reads<< >>. Restricted to in-domain acks, both models give 384 CTIs. In reachable states no map read is ever off its domain.Deviations from the plan
t_leader_commit's ack mapqis a ghost payload. The other two are real step parameters that no guard bounds, and no exporter could bound them.t_bump_term'st: nathas only the lower boundt > h.term, so the hole is filled with1..MaxTerm: under the guard that isRaft.tla's(h.term+1)..MaxTerm, and the constraint excludes any larger term.t_propose'scmd: Option<Seq<u8>>ranges over all byte strings, filled with anNCommands-element alphabet, which isRaft.tla's (A2).Test plan
tla/export/export.shwith the verus#53 build regeneratesGState_tla.*byte for byte.RaftExportMC.cfg,_deep_lc.cfg,_deep_reads.cfg, and both witness configurations, with the numbers above. Deep reads and the reads witness were also run with one worker for both models.tla/export/cti.sh: the export column of the CTI table.tla/export/oracle.sh a3andoracle.sh noa3: the two oracle columns and the "without (A3)" state counts (8,796,586 and 5,075,165 generated), all as tabulated, including 384 forinv_ack_persist_domon both sides.EXPORT.mdandREADME.mdreproduce the tables. The witnesses run with one worker; with four, the reads witness came out at 15 states. With one worker, the export'sRaft.cfganddeep_lcdiameters are still 18 and 20.cargo build,test,clippyandfmtare unaffected.🤖 Generated with Claude Code