You're viewing the readable version of this site. The interactive extras (search, diagrams, read-aloud) need JavaScript and a current browser. Enable JavaScript; if it is already enabled, update your browser.

Learn · All the Ways It Can Break

growing

Put the Network in the Model

Messages do not arrive in source order merely because the send calls do.

formal-methods, stateright, actors, distributed-systems, network-faults, learn

You will implement an Actor, emit messages and a retry timer, configure a lossy unordered network, inspect the reordering counterexample, and transfer the method to a different protocol. You will state which network behaviors and bounds remain outside the evidence.

Actors turn effects into commands

An actor receives an event, updates copy-on-write state, and emits commands through Out. During checking those commands update the modeled network and timer state; the Rust function itself performs no I/O.

rust code/all-the-ways-it-can-break/replicated-register-stateright/model.rs#actor model.rs The leader emits two values and a retry timer. The follower either assigns the received value or joins it with the current maximum.

An actor owns private state and reacts to messages one event at a time. The Stateright Actor API turns sends, timers, storage, and random choices into commands the checker can interpret.

The monotonic flag creates the negative control and repair from one model. The safety state remembers whether value 2 has ever arrived. Without that history, states value = 1 before 2 and value = 1 after 2 would look equal even though only the latter is a regression.

Configure the faults you mean

rust code/all-the-ways-it-can-break/replicated-register-stateright/model.rs#network-model model.rs ActorModel owns actors, network behavior, and properties. Loss is enabled deliberately; unordered duplication is the initial network's delivery semantics.

The shortest violating delivery order is Value(2), then Value(1). Message loss is not needed for this witness, but modeling it checks that dropping either message cannot create the same safety violation. For an invariant that does not inspect pending messages, indefinite delay can be observationally equivalent to loss; explicitly modeling both may add work without changing that property.

Fault model — predict which repair survives reordering.

Timers and liveness need restraint

set_timer makes timeout a possible checker action. It does not make timeout inevitable. A retry can support progress only with assumptions about which enabled actions eventually occur. A bounded safety run can show that retries, drops, and duplicate deliveries do not violate the invariant in its explored state graph; it does not establish real-time delivery or eventual convergence.

Network semantics are selectable. An ordered network can model per-link FIFO; an unordered nonduplicating network can omit redelivery. Choose the weakest behavior the real transport promises, then state excluded faults such as corruption, partitions longer than the model, actor crashes, or durable-state loss. A convenient stronger transport can erase the failure under study.

Unlike transfer: expiring a reservation

Model a coordinator and a worker for a reservation protocol. The coordinator sends Reserve(epoch) and later Cancel(epoch); a retry may duplicate either message. The worker must never resurrect a canceled epoch when an old reserve arrives late. Use explicit epoch state rather than copying the register's boolean has_seen_latest history.

Complete the transfer when:

  1. the broken worker has a concrete cancel-then-old-reserve counterexample;
  2. the repaired worker rejects commands older than its greatest observed epoch;
  3. a positive property or witness shows a fresh reservation can still activate;
  4. loss, duplication, ordering, timeout, crash, and depth assumptions appear in the verdict.

Lessons

  • Actor outputs make sends and timers visible to the model checker.
  • Network order is a model choice, not a consequence of source order.
  • Loss, duplication, timeout, crash, and storage behavior must be admitted explicitly.
  • History belongs in state when a property depends on what happened before.
  • Monotonic updates can make reordering and duplication harmless for a narrow claim.
  • Safety under bounded network exploration does not imply real-time liveness.

Practice

  1. Retrieval. What checker actions arise from sends, a lossy network, and a timer?
  2. Discrimination. When can explicit message loss be redundant for an invariant?
  3. Transfer. Build the reservation model and preserve its shortest broken trace beside the repair.

Worked answers

  1. Delivery actions, drop actions, and timeout actions; the duplicating network may redeliver an admitted envelope.
  2. When the property does not inspect network contents and unbounded delay has the same observable effect as loss.
  3. The essential trace delivers a cancel for epoch e, then an older or duplicate reserve for e; the repair records the greatest decided epoch and refuses resurrection.

References

  1. Stateright. Actor tutorial. — executable actors and checking
  2. Stateright. ActorModel API for 0.31.0. — actors, properties, faults, and boundaries
  3. Stateright. Network API for 0.31.0. — ordered, unordered, and duplicating semantics