-
Notifications
You must be signed in to change notification settings - Fork 24
feat: add #simulate command #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rnbguy
wants to merge
91
commits into
verse-lab:veil-2.0-preview
Choose a base branch
from
rnbguy:feat/simulate
base: veil-2.0-preview
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 56 commits
Commits
Show all changes
91 commits
Select commit
Hold shift + click to select a range
434f5e1
add #simulate command for random-walk state exploration
rnbguy f15aca5
lazy trace recording with replay-on-violation
rnbguy df4f8e5
try/catch error handling with seed reporting in simulate loop
rnbguy 543cce4
share helpers between #model_check and #simulate, add widget support
rnbguy 1e9c481
restore docstrings and inline comments removed during refactor
rnbguy 2f12dd7
uncomment violationIsError option in MutexViolation example
rnbguy c066bee
simplify assertion failure handling to single-pass in simulateOnceLoop
rnbguy 53cbc95
remove totalSteps tracking from simulate pipeline
rnbguy e2783dd
remove unused displayResultWidget, clean up formatting
rnbguy 542db5c
add SharedCounter example where #simulate outperforms #model_check
rnbguy b5c3bef
Merge branch 'veil-2.0-preview' into feat/simulate
rnbguy 2c1598e
fix: build
rnbguy 8201073
fix: qualify compilation status constructors
rnbguy a8e9419
feat: align command architecture with #model_check
rnbguy ed7f810
test: cover parity regressions
rnbguy 534c9f2
refactor: share executed path semantics
rnbguy 2fc5d47
refactor: share pure and runtime trace loops
rnbguy 96d39f0
feat: use runtime runner for command execution
rnbguy 7ad5f60
refactor: clean result rendering semantics
rnbguy 12adb4c
refactor: split simulation into modular files
rnbguy 55e15e4
feat: support assumptions checks
rnbguy 7f58696
feat: add simulation-native results and progress
rnbguy 6075426
refactor: add theorem-level soundness bridges
rnbguy 9dba342
fix: recreate temp build folders
rnbguy 4353e5f
refactor: emit prop-level soundness theorems
rnbguy a4483a8
refactor: make random selection proof-carrying
rnbguy b304781
refactor: simplify single-trace proof foundations
rnbguy 7ee56dc
refactor: prove single-trace engine soundness
rnbguy d26185f
feat: lift engine soundness through runtime
rnbguy 8f2c504
refactor: emit engine-level soundness theorem
rnbguy f05510e
refactor: remove bool soundness certificates
rnbguy 78542c0
refactor: prove runtime soundness directly
rnbguy 8ca3b6f
refactor: make simulate theorem assumptions-aware
rnbguy a379849
refactor: align simulate theorem boundary with command semantics
rnbguy 64f76af
fix: persist final progress metrics
rnbguy f2656c2
fix: encode trace budget termination
rnbguy 025d752
fix: use a single result log path
rnbguy 1fde08c
test: cover emitted mode behavior
rnbguy d81587c
refactor: drop unused path helpers
rnbguy dd97553
refactor: remove unused simulate names
rnbguy d09d7d2
chore: remove new proof warnings
rnbguy dcf6735
fix: make trace limits part of core results
rnbguy 41f2602
fix: align display trace-limit counts
rnbguy e9ad7d3
test: add simulate violation mode regression
rnbguy 797f9f6
fix(model-checker): isolate compiled command instances
rnbguy 7140a15
fix(simulate): keep default compilation running
rnbguy c27a938
fix(simulate): tighten handoff cancellation and parity
rnbguy ed23a67
fix(examples): replace SharedCounter with lease race examples
rnbguy 3f9605f
fix(examples): add simulate-friendly reliable broadcast
rnbguy 9971ba1
fix(simulate): preserve explicit default config values
rnbguy 6da6208
fix(simulate): show chosen seed in output
rnbguy 48fdf21
fix(simulate): short-circuit empty initial states
rnbguy 312d8e2
test(simulate): make interpreted mode explicit
rnbguy 17228a1
chore: reduce noises
rnbguy fd86b56
fix(simulate): align violation soundness with runtime semantics
rnbguy 6dd0370
fix(simulate): respect config bounds and omitted theory
rnbguy ec620dd
fix(simulate): use dedicated simulation result
rnbguy 0ebceb9
refactor(model-checker): share invariant violation helper
rnbguy 18746f9
refactor(simulate): restrict constrained system once
rnbguy ad7cc3f
refactor(model-checker): move state constraint helper
rnbguy ebfbe4b
refactor(model-checker): reuse state constraint helper
rnbguy e543551
refactor(simulate): reuse model checker result json
rnbguy bec1247
chore: merge upstream veil-2.0-preview
rnbguy b42bb43
fix(simulate): unify result json serialization
rnbguy 93793e5
refactor(model-checker): remove unused status prefix
rnbguy ea1dc6b
refactor(frontend): remove unnecessary prime from ident helper
rnbguy 8550732
refactor(simulation): use relational transition system directly
rnbguy 732188c
refactor(simulation): reuse execution outcome partitioning
rnbguy effe56d
refactor(simulation): use state monad for random traces
rnbguy 747c4cc
refactor(simulation): rename indexed trace helper
rnbguy 85a9dd6
docs(model-checker): document compiled command fields
rnbguy 956968e
chore(model-checker): remove redundant helpers
rnbguy 5c213c9
fix(simulation): clarify empty initial state result
rnbguy e6b0d6a
refactor(simulation): inline step decision logic
rnbguy cee1687
refactor(simulation): inline random path selection
rnbguy cf689c5
refactor(simulation): use relational trace validity
rnbguy 6c873e6
refactor(simulation): remove pure simulation loop
rnbguy 41be257
refactor(progress): split simulation payload
rnbguy 242d22b
refactor(progress): consolidate viewer rendering
rnbguy dbdae2c
test(simulation): avoid compiled-mode cases
rnbguy a2fd109
fix(model-checker): avoid per-command build folders
rnbguy b3ed49e
refactor(simulation): clarify config precedence
rnbguy e717e6c
refactor(simulation): consolidate handoff cleanup
rnbguy 535b237
test(simulation): add compiled smoke test
rnbguy 2abddc6
fix(simulation): structure no-initial result metadata
rnbguy 2e74826
fix(progress): preserve cancelled simulation metadata
rnbguy 9d47395
fix(widget): render simulation result metadata
rnbguy 9fdd830
refactor(simulation): derive result depth from traces
rnbguy 90cb9de
fix(model-checker): preserve compiled build cache
rnbguy a5f18e3
chore: merge upstream veil-2.0-preview
rnbguy 0d5d0f4
fix(simulation): generate executable definitions for simulate
rnbguy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| import Veil | ||
|
|
||
| /- | ||
| Original source/reference: | ||
| - Local modeling analogues: | ||
| - Examples/Ivy/DecentralizedLock.lean (epoched authority transfer) | ||
| - Examples/TLA/Raft.lean (leader failover) | ||
| - Production inspiration: etcd lease checkpoint persistence across leader | ||
| failover (etcd-io/etcd#13508) | ||
|
|
||
| Bug/race shape: | ||
| A leader checkpoints a lease's reduced remaining TTL. After failover, the new | ||
| leader forgets that checkpointed TTL and reconstructs the lease from the older | ||
| grant state, reviving a lease that should already be considered expired. | ||
|
|
||
| Why #simulate here: | ||
| The violating trace is short, but exhaustive search must branch over leaders, | ||
| leases, epochs, and recovery schedules. | ||
| -/ | ||
|
|
||
| veil module CheckpointLeaseFailover | ||
|
|
||
| type node | ||
| type epoch | ||
| type lease | ||
|
|
||
| instantiate epochOrd : TotalOrder epoch | ||
|
|
||
| individual leader : node | ||
| immutable individual initial_leader : node | ||
| immutable individual initial_epoch : epoch | ||
| relation current_epoch (e : epoch) | ||
| relation granted_until (l : lease) (e : epoch) | ||
| relation checkpointed_until (l : lease) (e : epoch) | ||
| relation active_on_leader (l : lease) | ||
|
|
||
| #gen_state | ||
|
|
||
| after_init { | ||
| leader := initial_leader | ||
| current_epoch E := E == initial_epoch | ||
| granted_until L E := false | ||
| checkpointed_until L E := false | ||
| active_on_leader L := false | ||
| } | ||
|
|
||
| action grantLease (l : lease) (expiry : epoch) { | ||
| require ∀ now, current_epoch now -> ¬ epochOrd.le expiry now | ||
| granted_until l E := E == expiry | ||
| active_on_leader l := true | ||
| } | ||
|
|
||
| action checkpointRemainingTTL (l : lease) (expiry : epoch) { | ||
| require active_on_leader l | ||
| require ∀ now, current_epoch now -> ¬ epochOrd.le expiry now | ||
| checkpointed_until l E := E == expiry | ||
| } | ||
|
|
||
| action failover (newLeader : node) (newEpoch : epoch) { | ||
| require newLeader != leader | ||
| require ∀ oldEpoch, current_epoch oldEpoch -> ¬ epochOrd.le newEpoch oldEpoch | ||
| leader := newLeader | ||
| current_epoch E := E == newEpoch | ||
| active_on_leader L := false | ||
| } | ||
|
|
||
| action recoverLeaseFromGrant (l : lease) (expiry : epoch) { | ||
| require granted_until l expiry | ||
| active_on_leader l := true | ||
| } | ||
|
|
||
| invariant [one_current_epoch] | ||
| ∀ (e1 e2 : epoch), current_epoch e1 ∧ current_epoch e2 -> e1 = e2 | ||
|
|
||
| safety [checkpointed_expiry_respected] | ||
| ∀ (l : lease) (expiry now : epoch), | ||
| checkpointed_until l expiry ∧ current_epoch now ∧ epochOrd.le expiry now -> | ||
| ¬ active_on_leader l | ||
|
|
||
| #gen_spec | ||
|
|
||
| -- model_check must branch over failovers, recovery choices, and many lease/epoch combinations. | ||
| -- set_option veil.violationIsError false in | ||
| -- #model_check { node := Fin 12, epoch := Fin 8, lease := Fin 8 } | ||
| -- { initial_leader := (0 : Fin 12), initial_epoch := (0 : Fin 8) } | ||
|
|
||
| -- simulate quickly finds the stale-recovery bug after failover. | ||
| set_option veil.violationIsError false in | ||
| #simulate { node := Fin 12, epoch := Fin 8, lease := Fin 8 } | ||
| { initial_leader := (0 : Fin 12), initial_epoch := (0 : Fin 8) } | ||
| (seed := 23) (maxTraces := 2000) (maxSteps := 10) | ||
|
|
||
| end CheckpointLeaseFailover |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| import Veil | ||
|
|
||
| /- | ||
| Original source/reference: | ||
| - Closest local modeling analogue: Examples/Ivy/DecentralizedLock.lean | ||
| - Production reference: etcd KeepAlive vs lease-expiry revocation race | ||
| (etcd-io/etcd#21389, issue #14758) | ||
|
|
||
| Bug/race shape: | ||
| A client still has keys attached to a lease when revocation starts. A late | ||
| keepalive succeeds after revocation has already removed the keys, so the client | ||
| appears renewed even though its data is gone. | ||
|
|
||
| Why #simulate here: | ||
| The bad trace is only a handful of steps, but exhaustive search must branch over | ||
| clients, keys, revoke timing, and keepalive interleavings. | ||
| -/ | ||
|
|
||
| veil module LeaseKeepaliveRace | ||
|
|
||
| type client | ||
| type key | ||
|
|
||
| relation lease_alive (c : client) | ||
| relation revoke_started (c : client) | ||
| relation keepalive_succeeded (c : client) | ||
| relation key_attached (c : client) (k : key) | ||
| relation key_present (k : key) | ||
|
|
||
| #gen_state | ||
|
|
||
| after_init { | ||
| lease_alive C := false | ||
| revoke_started C := false | ||
| keepalive_succeeded C := false | ||
| key_attached C K := false | ||
| key_present K := false | ||
| } | ||
|
|
||
| action grantLease (c : client) { | ||
| require !(lease_alive c) | ||
| lease_alive c := true | ||
| revoke_started c := false | ||
| keepalive_succeeded c := false | ||
| } | ||
|
|
||
| action attachKey (c : client) (k : key) { | ||
| require lease_alive c | ||
| key_attached c k := true | ||
| key_present k := true | ||
| } | ||
|
|
||
| action startRevoke (c : client) { | ||
| require lease_alive c | ||
| revoke_started c := true | ||
| lease_alive c := false | ||
| } | ||
|
|
||
| action deleteKey (c : client) (k : key) { | ||
| require revoke_started c | ||
| require key_attached c k | ||
| key_present k := false | ||
| } | ||
|
|
||
| action keepAlive (c : client) { | ||
| require revoke_started c | ||
| keepalive_succeeded c := true | ||
| lease_alive c := true | ||
| } | ||
|
|
||
| safety [renewal_keeps_keys_live] | ||
| ∀ (c : client) (k : key), keepalive_succeeded c ∧ key_attached c k -> key_present k | ||
|
|
||
| #gen_spec | ||
|
|
||
| -- model_check must branch over clients, keys, revoke order, and late keepalives. | ||
| -- set_option veil.violationIsError false in | ||
| -- #model_check { client := Fin 8, key := Fin 8 } {} | ||
|
|
||
| -- simulate usually hits the keepalive-after-revoke race in a short trace. | ||
| set_option veil.violationIsError false in | ||
| #simulate { client := Fin 8, key := Fin 8 } {} | ||
| (seed := 11) (maxTraces := 300) (maxSteps := 12) | ||
|
|
||
| end LeaseKeepaliveRace |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| import Veil | ||
|
|
||
| /- | ||
| Original source/reference: | ||
| - Local analogue: Examples/Ivy/ReliableBroadcast.lean | ||
| - External family reference: tlaplus/Examples/specifications/bcastByz/bcastByz.tla | ||
|
|
||
| Bug/race shape: | ||
| This simulate-focused variant keeps the initial/echo/vote/deliver structure, but | ||
| intentionally uses weak quorum rules. An equivocating originator can get two | ||
| different values delivered by different receivers. | ||
|
|
||
| Why #simulate here: | ||
| The violating trace is short, but exhaustive search must branch over broadcast, | ||
| echo, vote, and delivery orderings across many nodes and values. | ||
| -/ | ||
|
|
||
| veil module ReliableBroadcastSim | ||
|
|
||
| type node | ||
| type value | ||
|
|
||
| immutable individual originator : node | ||
|
|
||
| relation initial_msg (src : node) (dst : node) (v : value) | ||
| relation echo_msg (src : node) (dst : node) (v : value) | ||
| relation vote_msg (src : node) (dst : node) (v : value) | ||
| relation delivered (dst : node) (v : value) | ||
|
|
||
| #gen_state | ||
|
|
||
| after_init { | ||
| initial_msg S D V := false | ||
| echo_msg S D V := false | ||
| vote_msg S D V := false | ||
| delivered D V := false | ||
| } | ||
|
|
||
| action initialSend (dst : node) (v : value) { | ||
| require ∀ V, !(initial_msg originator dst V) | ||
| initial_msg originator dst v := true | ||
| } | ||
|
|
||
| action echo (src : node) (v : value) { | ||
| require initial_msg originator src v | ||
| echo_msg src D v := true | ||
| } | ||
|
|
||
| action vote (observer : node) (v : value) { | ||
| require ∃ (n1 n2 : node), n1 != n2 ∧ echo_msg n1 observer v ∧ echo_msg n2 observer v | ||
| vote_msg observer D v := true | ||
| } | ||
|
|
||
| action deliver (observer : node) (v : value) { | ||
| require ∃ (n1 n2 : node), n1 != n2 ∧ vote_msg n1 observer v ∧ vote_msg n2 observer v | ||
| delivered observer v := true | ||
| } | ||
|
|
||
| safety [agreement] | ||
| ∀ (n1 n2 : node) (v1 v2 : value), delivered n1 v1 ∧ delivered n2 v2 -> v1 = v2 | ||
|
|
||
| #gen_spec | ||
|
|
||
| -- model_check must enumerate many broadcast, echo, vote, and delivery schedules. | ||
| -- set_option veil.violationIsError false in | ||
| -- #model_check { node := Fin 10, value := Fin 2 } { originator := (0 : Fin 10) } | ||
|
|
||
| -- simulate quickly finds an equivocation trace with the weak quorum rules above. | ||
| set_option veil.violationIsError false in | ||
| #simulate { node := Fin 10, value := Fin 2 } { originator := (0 : Fin 10) } | ||
| (seed := 41) (maxTraces := 2000) (maxSteps := 24) | ||
|
|
||
| end ReliableBroadcastSim |
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
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
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
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
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current
Progressstructure feels somewhat monolithic, especially with simulation-specific fields being added directly to it.Would it make sense to model this as an inductive type instead, with separate constructors for model checking and simulation (each carrying their own payload)? Or were there specific reasons for not structuring it this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
41be257