minerva 0.2.0

Causal ordering for distributed systems
extern crate alloc;

use alloc::vec::Vec;

use crate::metis::{Dotted, Rhapsody};

use super::wire::round_trip_rhapsody;
use super::{Fleet, REPLICAS};

/// After the tape, gossip the fleet to convergence and assert the convergence
/// laws: fold-order independence, one visible order, a surviving wire law,
/// and the strong-list verdict over every order the whole run observed
/// (S288): one witness total order must embed them all.
pub(super) fn assert_convergence(fleet: &mut Fleet) {
    let states: Vec<Dotted<Rhapsody>> = fleet.live.iter().map(|r| r.state().clone()).collect();
    // Every pairwise merge from the pre-convergence snapshot is observed
    // first: the in-place loop below walks only one merge path (the first
    // replica absorbs the second, then the third meets their join), and a
    // transient contradiction in a skipped pair could hide behind the
    // healed full join (the S288 review's second finding; the ledger
    // exhibit pinning the detection power is
    // `strong_list::examples::test_a_skipped_pairwise_merge_can_hide_a_contradiction`).
    for i in 0..REPLICAS {
        for j in 0..REPLICAS {
            if i != j {
                let pairwise = states[i].merge(&states[j]);
                let order = pairwise.store().order();
                let _ = fleet.ledger.observe(&order);
            }
        }
    }
    let mut states = states;
    for _ in 0..REPLICAS {
        for i in 0..REPLICAS {
            for j in 0..REPLICAS {
                if i != j {
                    states[i] = states[i].merge(&states[j]);
                    // Every intermediate post-merge order is an observed
                    // state: a transient contradiction that later merges
                    // would heal must not escape the oracle (the S288
                    // review's first finding).
                    let order = states[i].store().order();
                    let _ = fleet.ledger.observe(&order);
                }
            }
        }
    }

    let forward = states
        .iter()
        .fold(Dotted::<Rhapsody>::new(), |acc, s| acc.merge(s));
    let backward = states
        .iter()
        .rev()
        .fold(Dotted::<Rhapsody>::new(), |acc, s| acc.merge(s));
    assert_eq!(forward, backward, "the fold must not depend on order");

    let target = forward.store().order();
    for state in &states {
        assert_eq!(
            state.store().order(),
            target,
            "every converged replica reads the one order",
        );
    }

    round_trip_rhapsody(forward.store());

    let _ = fleet.ledger.observe(&target);
    if let Err(contradiction) = fleet.ledger.verdict() {
        panic!(
            "the run's observed orders admit no single total order \
             (the strong list specification's order clause): {contradiction:?}",
        );
    }
}