minerva 0.2.0

Causal ordering for distributed systems
//! The single-threaded shell: `LocalClock` examples (S188). The semantics
//! under test are the shared fold's, already covered by the `Clock` suites
//! and the S86 proofs; these examples pin the shell's own surface (parity of
//! the four operations, the all-or-nothing bounded receive, the stats
//! shape), and the shell-agreement property in `properties/clock.rs` pins
//! that the two shells tell one story on any tape.

extern crate alloc;

use crate::kairos::{InvalidStationId, Kairos, LocalClock, TickCounter, VirtualTimeSource};

#[test]
fn test_local_clock_refuses_station_zero() {
    let refused = LocalClock::new(TickCounter::new(), 0);
    assert!(matches!(refused, Err(InvalidStationId)));
    let refused = LocalClock::with_warning_threshold(TickCounter::new(), 0, 1);
    assert!(matches!(refused, Err(InvalidStationId)));
}

#[test]
fn test_local_mints_are_monotonic_under_backward_skew() {
    let source = VirtualTimeSource::new(100);
    let driver = source.clone();
    let clock = LocalClock::new(source, 3).unwrap();

    let first = clock.now(0u16);
    driver.set(5); // the source moves backward; the output must not
    let second = clock.now(0u16);
    assert!(second > first, "monotonic under backward skew");
    assert_eq!(
        second.physical(),
        first.physical(),
        "a backward reading is never adopted"
    );
    assert!(
        clock.stats().max_backward_skew_ns > 0,
        "the skew is reported, not corrected"
    );
}

#[test]
fn test_local_after_dominates_the_remote() {
    let clock = LocalClock::new(TickCounter::new(), 3).unwrap();
    let remote = Kairos::new(500, 7, 9, 0u16);
    let minted = clock.after(remote, 0u16);
    assert!(minted > remote, "after() strictly dominates its remote");
    assert_eq!(clock.station_id(), 3);
    assert_eq!(minted.station_id(), 3);
}

#[test]
fn test_local_observe_advances_without_minting() {
    let clock = LocalClock::new(TickCounter::new(), 3).unwrap();
    let remote = Kairos::new(500, 7, 9, 0u16);
    clock.observe(remote);
    let minted = clock.now(0u16);
    assert!(minted > remote, "a mint after observe dominates the remote");
}

#[test]
fn test_local_try_observe_rejection_leaves_the_clock_unchanged() {
    let source = VirtualTimeSource::new(100);
    let clock = LocalClock::new(source, 3).unwrap();
    let before = clock.now(0u16);

    let far_future = Kairos::new(1_000_000, 0, 9, 0u16);
    let refused = clock.try_observe(far_future, 10);
    assert!(refused.is_err(), "skew beyond the bound is refused");

    let after = clock.now(0u16);
    assert!(
        after.physical() < far_future.physical(),
        "the refused remote dragged nothing forward"
    );
    assert!(after > before, "local monotonicity is undisturbed");
}

#[test]
fn test_local_stats_report_first_attempt_commitment() {
    let clock = LocalClock::new(TickCounter::new(), 3).unwrap();
    assert_eq!(
        clock.stats().peak_attempts,
        0,
        "nothing committed, nothing attempted"
    );
    let _ = clock.now(0u16);
    assert_eq!(
        clock.stats().peak_attempts,
        1,
        "a Cell commit always succeeds on its first attempt"
    );
}