rhi

Coordinated trade for connected markets
git clone https://radroots.dev/git/rhi.git
Log | Files | Refs | README | LICENSE

services_hardening_reconciliation_outcome_contract.rs (4747B)


      1 #![forbid(unsafe_code)]
      2 
      3 use rhi::RHI_RECONCILIATION_OUTCOME_CONTRACT_VERSION;
      4 use serde_json::json;
      5 
      6 const CONTRACT: &str =
      7     include_str!("../contracts/services_hardening/reconciliation_outcome.v1.json");
      8 const ROOT: &str = include_str!("../src/lib.rs");
      9 const SOURCE: &str = include_str!("../src/reconciliation_reducer.rs");
     10 const README: &str = include_str!("../README");
     11 
     12 #[test]
     13 fn machine_contract_freezes_the_complete_step_194_boundary() {
     14     let contract: serde_json::Value = serde_json::from_str(CONTRACT).expect("contract");
     15     assert_eq!(contract["schema"], "radroots.rhi.reconciliation-outcome");
     16     assert_eq!(contract["schema_version"], 1);
     17     assert_eq!(
     18         contract["contract_version"],
     19         RHI_RECONCILIATION_OUTCOME_CONTRACT_VERSION
     20     );
     21     assert_eq!(
     22         contract["coverage"],
     23         json!(["missing", "partial", "scope_satisfied", "unsupported"])
     24     );
     25     assert_eq!(
     26         contract["outcome"],
     27         json!(["valid", "invalid", "indeterminate"])
     28     );
     29     assert_eq!(
     30         contract["precedence"],
     31         json!([
     32             "manifest_coverage",
     33             "projection_digest_availability",
     34             "shared_evidence_state",
     35             "reducer_issue_or_claim_ambiguity",
     36             "claim_presence",
     37             "clean_active_claim",
     38             "clean_cancelled_claim",
     39             "unresolved_claim"
     40         ])
     41     );
     42     assert_eq!(
     43         contract["decision"]["clean_active_claim"],
     44         json!(["valid", "scope_satisfied"])
     45     );
     46     assert_eq!(
     47         contract["decision"]["clean_cancelled_claim"],
     48         json!(["invalid", "agreement_claim_cancelled"])
     49     );
     50     for branch in [
     51         "missing",
     52         "partial",
     53         "unsupported",
     54         "projection_digest_unavailable",
     55         "shared_evidence_missing",
     56         "shared_evidence_partial",
     57         "shared_schema_unsupported",
     58         "reducer_issue_or_claim_ambiguity",
     59         "claim_missing",
     60         "claim_unresolved",
     61     ] {
     62         assert_eq!(
     63             contract["decision"][branch][0], "indeterminate",
     64             "{branch} must remain fail closed"
     65         );
     66     }
     67     assert_eq!(contract["reason_inventory"]["cardinality"], 1);
     68     assert_eq!(contract["reason_inventory"]["closed"], true);
     69     assert_eq!(
     70         contract["reason_inventory"]["codes"],
     71         json!([
     72             "required_evidence_missing",
     73             "required_source_incomplete",
     74             "required_source_unsupported",
     75             "projection_digest_unavailable",
     76             "governing_schema_unsupported",
     77             "reducer_issue_unresolved",
     78             "agreement_claim_missing",
     79             "agreement_claim_unresolved",
     80             "scope_satisfied",
     81             "agreement_claim_cancelled"
     82         ])
     83     );
     84     assert_eq!(contract["result"]["caller_forgeable"], false);
     85     assert_eq!(contract["result"]["retains_projection"], true);
     86     for effect in [
     87         "sqlite",
     88         "filesystem",
     89         "source_or_relay",
     90         "network",
     91         "task_spawn",
     92         "ambient_clock",
     93         "ambient_entropy",
     94     ] {
     95         assert_eq!(contract["effects"][effect], false, "effect {effect}");
     96     }
     97 }
     98 
     99 #[test]
    100 fn outcome_boundary_is_sealed_typed_redacted_and_total() {
    101     for required in [
    102         "RhiReconciliationEvaluation",
    103         "RhiReconciliationCoverage",
    104         "RhiReconciliationOutcome",
    105         "RhiReconciliationReasonCode",
    106         "RHI_RECONCILIATION_OUTCOME_CONTRACT_VERSION",
    107         "evaluate_rhi_reconciliation_claim",
    108     ] {
    109         assert!(ROOT.contains(required), "root API is missing {required}");
    110     }
    111     for required in [
    112         "projection: RhiReconciliationProjection",
    113         "claim_mutation_id: MutationId",
    114         "reason_codes: [RhiReconciliationReasonCode; 1]",
    115         "fn classify_evaluation(",
    116         "RadrootsTradeEvidenceStateV1::UnsupportedVersion",
    117         "RhiReconciliationCoverage::ScopeSatisfied",
    118         "(Invalid, AgreementClaimCancelled)",
    119         "(Indeterminate, AgreementClaimUnresolved)",
    120     ] {
    121         assert!(
    122             SOURCE.contains(required),
    123             "outcome boundary is missing {required}"
    124         );
    125     }
    126     for forbidden in [
    127         "sqlx::",
    128         "std::fs",
    129         "std::net",
    130         "tokio::",
    131         "SystemTime",
    132         "thread_rng",
    133         "OsRng",
    134         "pub fn new(",
    135         "pub const fn new(",
    136         "Result<RhiReconciliationEvaluation",
    137     ] {
    138         assert!(
    139             !SOURCE.contains(forbidden),
    140             "outcome boundary gained forbidden authority {forbidden}"
    141         );
    142     }
    143     assert!(README.contains("## Pure reconciliation reducer"));
    144     assert!(README.contains(
    145         "[`reconciliation_outcome.v1.json`](contracts/services_hardening/reconciliation_outcome.v1.json)"
    146     ));
    147 }