minerva 0.2.0

Causal ordering for distributed systems
//! Sealed duplicate recognition and retention-horizon cases.

use crate::metis::Vouched;
use alloc::vec::Vec;

use super::*;
use crate::metis::dot::RawDot;

/// Drives one deterministic epoch cycle to its seal.
fn seal_one(epochs: &mut Epochs, stability: &Stability, dot: Dot, rank: Kairos) -> EpochAddress {
    let declaration = epochs
        .declare(dot, rank, stability, &Cut::bottom())
        .expect("licensed");
    let mut delivered = declaration.cut().as_vector().clone();
    delivered.observe(dot.station(), dot.counter());
    let delivered = Cut::from_witnessed(delivered);
    let mut progressed = stability.clone();
    for station in ROSTER {
        progressed.report_cut(station, &delivered).unwrap();
        epochs
            .confirm(
                declaration.address(),
                &Vouched::trust(station, delivered.clone()),
            )
            .unwrap();
    }
    let own = delivered.as_vector().get(1);
    let _ = epochs.adopt(1, own, &progressed).expect("confirmed");
    for station in [2, 3] {
        epochs
            .adopt_report(
                declaration.address(),
                &Vouched::trust(station, delivered.as_vector().get(station)),
            )
            .unwrap();
    }
    let sealed = epochs.try_seal(&progressed).expect("seals");
    assert_eq!(sealed.declaration(), declaration.address());
    declaration.address()
}

#[test]
fn the_sealed_join_is_the_duplicate_recognizer() {
    let mut epochs = machine();
    let mut stability = tracker();
    for station in ROSTER {
        stability.report_cut(station, &top()).unwrap();
    }
    let epoch = seal_one(
        &mut epochs,
        &stability,
        d(1, 10),
        Kairos::new(5, 0, 1, 0u16),
    );

    assert_eq!(epochs.recognize(epoch, d(2, 9)), Ok(()));
    assert_eq!(epochs.recognize(epoch, d(2, 9)), Ok(()));
    assert_eq!(
        epochs.recognize(epoch, d(2, 10)),
        Err(EpochRefusal::AddressMiss {
            epoch,
            dot: RawDot::new(2, 10)
        })
    );
    let replay = machine()
        .declare(
            d(1, 10),
            Kairos::new(5, 0, 1, 0u16),
            &stability,
            &Cut::bottom(),
        )
        .unwrap();
    assert_eq!(epochs.deliver(replay, &stability, &Cut::bottom()), Ok(()));
    assert_eq!(epochs.confirm(epoch, &Vouched::trust(2, top())), Ok(()));
    assert_eq!(epochs.adopt_report(epoch, &Vouched::trust(2, 9)), Ok(()));

    let mut foreign_stability = tracker();
    let foreign_cut = cut(&[(1, 8), (2, 8), (3, 8)]);
    for station in ROSTER {
        foreign_stability.report_cut(station, &foreign_cut).unwrap();
    }
    let foreign = machine()
        .declare(
            d(2, 9),
            Kairos::new(9, 0, 2, 0u16),
            &foreign_stability,
            &Cut::bottom(),
        )
        .unwrap();
    assert_eq!(
        epochs.deliver(foreign.clone(), &stability, &Cut::bottom()),
        Err(EpochRefusal::AddressMiss {
            epoch: foreign.address(),
            dot: foreign.dot().into(),
        })
    );

    // Window traffic remains the shadow's responsibility.
    let next = epochs
        .declare(
            d(1, 11),
            Kairos::new(7, 0, 1, 0u16),
            &stability,
            &Cut::bottom(),
        )
        .unwrap();
    assert_eq!(
        epochs.recognize(next.address(), d(1, 1)),
        Err(EpochRefusal::WindowOpen {
            open: next.address()
        })
    );
}

#[test]
fn the_lineage_holds_the_horizon_and_refuses_below_it() {
    let mut epochs = machine();
    let mut stability = tracker();
    for station in ROSTER {
        stability.report_cut(station, &top()).unwrap();
    }
    let first = seal_one(
        &mut epochs,
        &stability,
        d(1, 10),
        Kairos::new(5, 0, 1, 0u16),
    );
    let second = seal_one(
        &mut epochs,
        &stability,
        d(2, 10),
        Kairos::new(6, 0, 2, 0u16),
    );
    let third = seal_one(
        &mut epochs,
        &stability,
        d(3, 10),
        Kairos::new(7, 0, 3, 0u16),
    );

    let retained: Vec<EpochAddress> = epochs.sealed().map(SealedEpoch::declaration).collect();
    assert_eq!(retained, alloc::vec![second, third]);

    assert_eq!(epochs.recognize(second, d(1, 9)), Ok(()));
    assert_eq!(epochs.recognize(third, d(1, 9)), Ok(()));
    assert_eq!(
        epochs.recognize(first, d(1, 1)),
        Err(EpochRefusal::BeyondHorizon { epoch: first })
    );
    let reused = epochs
        .declare(
            first.declaration(),
            Kairos::new(10, 0, first.declaration().station(), 0u16),
            &stability,
            &Cut::bottom(),
        )
        .unwrap();
    assert_ne!(reused.address(), first);
    assert_eq!(
        epochs.recognize(first, d(1, 1)),
        Err(EpochRefusal::BeyondHorizon { epoch: first })
    );
    assert_eq!(
        epochs.recognize(reused.address(), d(1, 1)),
        Err(EpochRefusal::WindowOpen {
            open: reused.address()
        })
    );
    let never = machine()
        .declare(
            d(2, 10),
            Kairos::new(9, 0, 2, 0u16),
            &stability,
            &Cut::bottom(),
        )
        .unwrap()
        .address();
    assert_eq!(
        epochs.recognize(never, d(1, 1)),
        Err(EpochRefusal::BeyondHorizon { epoch: never })
    );
}