telosieve 0.2.0-rc.4

Read-only infrastructure instruction evaluation that refuses when trusted evidence cannot agree
Documentation
use std::{
    collections::{BTreeMap, BTreeSet},
    fs,
};

use telosieve::{
    certificate::Decision,
    engine::{RunError, run_scenario},
    protocol::{AuthorityKind, Scenario},
};

fn fixture(name: &str) -> Scenario {
    serde_json::from_slice(&fs::read(format!("scenarios/{name}")).unwrap()).unwrap()
}

#[test]
fn registered_adversarial_fault_classes_fail_closed_or_refuse() {
    let poisoned = run_scenario(&fixture("poisoned-goal.json")).unwrap();
    assert_eq!(poisoned.decision, Decision::Refused);

    let mut stale = fixture("benign.json");
    stale.evaluation_time = stale.authorities[0].expires_at;
    assert!(matches!(run_scenario(&stale), Err(RunError::Protocol(_))));

    let mut omitted = fixture("benign.json");
    omitted
        .authorities
        .retain(|envelope| envelope.kind != AuthorityKind::Phenotype);
    assert!(matches!(run_scenario(&omitted), Err(RunError::Protocol(_))));

    let mut forged = fixture("benign.json");
    forged.authorities[1].signature.replace_range(..2, "00");
    assert!(matches!(run_scenario(&forged), Err(RunError::Protocol(_))));

    let weakened = run_scenario(&fixture("weakened-viability.json")).unwrap();
    assert_eq!(weakened.decision, Decision::Refused);
    assert_eq!(weakened.metrics.unsafe_approvals, 0);
    assert_eq!(weakened.metrics.hypothesis_count, 5);
    assert!(weakened.hypotheses.iter().any(|hypothesis| {
        hypothesis.suspected == vec![AuthorityKind::Viability]
            && hypothesis.suspected_fault_domains == vec!["lab-domain"]
            && hypothesis.suspected_issuers == vec!["viability-lab", "viability-peer"]
            && hypothesis.proposed_transition.is_some()
            && hypothesis
                .checker
                .as_ref()
                .is_some_and(|checker| !checker.safe)
    }));
    let benign_domains = run_scenario(&fixture("benign.json")).unwrap();
    assert_eq!(benign_domains.decision, Decision::Applied);
    assert_eq!(benign_domains.metrics.false_refusals, 0);
    assert!(benign_domains.hypotheses.iter().any(|hypothesis| {
        hypothesis.suspected_fault_domains == vec!["lab-domain"]
            && hypothesis.excluded_issuers == vec!["viability-lab", "viability-peer"]
    }));

    let cross_domain = run_scenario(&fixture("all-viability-domains-weakened.json")).unwrap();
    assert_eq!(cross_domain.decision, Decision::Refused);
    assert_eq!(cross_domain.metrics.unsafe_approvals, 0);
    assert!(cross_domain.hypotheses.iter().all(|hypothesis| {
        hypothesis.checker.as_ref().is_some_and(|checker| {
            !checker.safe
                && checker
                    .reasons
                    .iter()
                    .any(|reason| reason.contains("stable key continuity failed: cluster/epoch"))
        })
    }));

    let mut missing_domain = fixture("benign.json");
    missing_domain
        .fault_declaration
        .viability_fault_domains
        .remove("viability-peer");
    assert!(matches!(
        run_scenario(&missing_domain),
        Err(RunError::FaultDeclaration(_))
    ));
    let mut unknown_domain = fixture("poisoned-goal.json");
    unknown_domain
        .fault_declaration
        .goal_fault_domains
        .insert("goal-ghost".into(), "goal-ghost-domain".into());
    assert!(matches!(
        run_scenario(&unknown_domain),
        Err(RunError::FaultDeclaration(_))
    ));

    let partitioned = run_scenario(&fixture("partitioned-phenotype.json")).unwrap();
    assert_eq!(partitioned.decision, Decision::Applied);

    let mut equivocation = fixture("benign.json");
    equivocation
        .authorities
        .push(equivocation.authorities[0].clone());
    assert!(matches!(
        run_scenario(&equivocation),
        Err(RunError::Protocol(_))
    ));

    let mut correlated = fixture("poisoned-goal.json");
    correlated.fault_declaration.maximum_faults = 2;
    correlated.fault_declaration.maximum_hypotheses = 16;
    correlated.fault_declaration.suspectable = BTreeSet::from([
        AuthorityKind::Goal,
        AuthorityKind::Phenotype,
        AuthorityKind::Viability,
    ]);
    correlated.fault_declaration.viability_fault_domains = BTreeMap::from([
        ("viability-lab".into(), "lab-domain".into()),
        ("viability-peer".into(), "lab-domain".into()),
        ("viability-review".into(), "review-domain".into()),
    ]);
    assert_eq!(
        run_scenario(&correlated).unwrap().decision,
        Decision::Refused
    );
}

#[test]
fn goal_domains_preserve_agreement_and_reject_invalid_or_divergent_evidence() {
    let poisoned = run_scenario(&fixture("poisoned-goal.json")).unwrap();
    assert_eq!(poisoned.metrics.hypothesis_count, 3);
    for (domain, issuer) in [
        ("goal-lab-domain", "goal-lab"),
        ("goal-review-domain", "goal-review"),
    ] {
        assert!(poisoned.hypotheses.iter().any(|hypothesis| {
            hypothesis.suspected == vec![AuthorityKind::Goal]
                && hypothesis.suspected_fault_domains == vec![domain]
                && hypothesis.suspected_issuers == vec![issuer]
                && hypothesis.proposed_transition.is_some()
        }));
    }

    let mut missing_domain = fixture("poisoned-goal.json");
    missing_domain
        .fault_declaration
        .goal_fault_domains
        .remove("goal-review");
    assert!(matches!(
        run_scenario(&missing_domain),
        Err(RunError::FaultDeclaration(_))
    ));

    let benign_review = fixture("benign.json")
        .authorities
        .into_iter()
        .find(|authority| authority.issuer == "goal-review")
        .unwrap();
    let mut divergent = fixture("poisoned-goal.json");
    *divergent
        .authorities
        .iter_mut()
        .find(|authority| authority.issuer == "goal-review")
        .unwrap() = benign_review;
    assert!(matches!(
        run_scenario(&divergent),
        Err(RunError::Protocol(_))
    ));

    let mut correlated = fixture("benign.json");
    correlated
        .fault_declaration
        .suspectable
        .insert(AuthorityKind::Goal);
    correlated.fault_declaration.goal_fault_domains = BTreeMap::from([
        ("goal-lab".into(), "shared-goal-domain".into()),
        ("goal-review".into(), "shared-goal-domain".into()),
    ]);
    correlated.fault_declaration.maximum_hypotheses = 4;
    let certificate = run_scenario(&correlated).unwrap();
    assert_eq!(certificate.decision, Decision::Refused);
    assert!(certificate.hypotheses.iter().any(|hypothesis| {
        hypothesis.suspected_fault_domains == vec!["shared-goal-domain"]
            && hypothesis.proposed_transition.is_none()
    }));
}

#[test]
fn deletion_requires_exact_bound_authorization_with_a_surviving_domain() {
    let authorized = run_scenario(&fixture("authorized-deletion.json")).unwrap();
    assert_eq!(authorized.decision, Decision::Applied);
    assert_eq!(authorized.metrics.unsafe_approvals, 0);
    assert!(authorized.final_state.replicas.values().all(|values| {
        values.contains_key("cluster/epoch") && !values.contains_key("user/message")
    }));
    assert!(
        authorized
            .hypotheses
            .iter()
            .all(|hypothesis| { hypothesis.authorized_deletions == vec!["user/message"] })
    );

    let unauthorized = run_scenario(&fixture("unauthorized-deletion.json")).unwrap();
    assert_eq!(unauthorized.decision, Decision::Refused);
    assert_eq!(unauthorized.metrics.unsafe_approvals, 0);

    let deletion_evidence: Vec<_> = fixture("authorized-deletion.json")
        .authorities
        .into_iter()
        .filter(|authority| authority.kind == AuthorityKind::Deletion)
        .collect();
    let mut replayed = fixture("benign.json");
    replayed
        .fault_declaration
        .suspectable
        .insert(AuthorityKind::Deletion);
    replayed.fault_declaration.deletion_fault_domains = BTreeMap::from([
        ("deletion-lab".into(), "deletion-lab-domain".into()),
        ("deletion-review".into(), "deletion-review-domain".into()),
    ]);
    replayed.fault_declaration.maximum_hypotheses = 5;
    replayed.authorities.extend(deletion_evidence);
    assert!(matches!(
        run_scenario(&replayed),
        Err(RunError::Protocol(_))
    ));

    let mut missing_domain = fixture("authorized-deletion.json");
    missing_domain
        .fault_declaration
        .deletion_fault_domains
        .remove("deletion-review");
    assert!(matches!(
        run_scenario(&missing_domain),
        Err(RunError::FaultDeclaration(_))
    ));

    let mut correlated = fixture("authorized-deletion.json");
    correlated.fault_declaration.deletion_fault_domains = BTreeMap::from([
        ("deletion-lab".into(), "shared-deletion-domain".into()),
        ("deletion-review".into(), "shared-deletion-domain".into()),
    ]);
    let certificate = run_scenario(&correlated).unwrap();
    assert_eq!(certificate.decision, Decision::Refused);
    assert_eq!(certificate.metrics.false_refusals, 1);
    assert!(certificate.hypotheses.iter().any(|hypothesis| {
        hypothesis.suspected_fault_domains == vec!["shared-deletion-domain"]
            && hypothesis.authorized_deletions.is_empty()
    }));
}