chio-web3 0.1.2

Chio web3 settlement, anchoring, and contract-surface artifacts
Documentation
use std::collections::HashSet;

use serde::{Deserialize, Serialize};

use crate::error::Web3ContractError;
use crate::settlement::Web3SettlementLifecycleState;
use crate::validation::{ensure_non_empty, ensure_unique_strings};

pub const CHIO_WEB3_QUALIFICATION_MATRIX_SCHEMA: &str = "chio.web3-qualification-matrix.v1";

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Web3QualificationOutcome {
    Pass,
    FailClosed,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Web3QualificationCase {
    pub id: String,
    pub name: String,
    pub requirement_ids: Vec<String>,
    pub lifecycle_state: Web3SettlementLifecycleState,
    pub expected_outcome: Web3QualificationOutcome,
    pub observed_outcome: Web3QualificationOutcome,
    pub notes: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Web3QualificationMatrix {
    pub schema: String,
    pub trust_profile_id: String,
    pub contract_package_id: String,
    pub cases: Vec<Web3QualificationCase>,
}
pub fn validate_web3_qualification_matrix(
    matrix: &Web3QualificationMatrix,
) -> Result<(), Web3ContractError> {
    if matrix.schema != CHIO_WEB3_QUALIFICATION_MATRIX_SCHEMA {
        return Err(Web3ContractError::UnsupportedSchema(matrix.schema.clone()));
    }
    ensure_non_empty(
        &matrix.trust_profile_id,
        "web3_qualification_matrix.trust_profile_id",
    )?;
    ensure_non_empty(
        &matrix.contract_package_id,
        "web3_qualification_matrix.contract_package_id",
    )?;
    if matrix.cases.is_empty() {
        return Err(Web3ContractError::MissingField(
            "web3_qualification_matrix.cases",
        ));
    }
    let mut case_ids = HashSet::new();
    for case in &matrix.cases {
        ensure_non_empty(&case.id, "web3_qualification_matrix.case.id")?;
        ensure_non_empty(&case.name, "web3_qualification_matrix.case.name")?;
        ensure_non_empty(&case.notes, "web3_qualification_matrix.case.notes")?;
        if !case_ids.insert(case.id.as_str()) {
            return Err(Web3ContractError::DuplicateValue(case.id.clone()));
        }
        if case.requirement_ids.is_empty() {
            return Err(Web3ContractError::InvalidQualificationCase(format!(
                "case {} must cite at least one requirement id",
                case.id
            )));
        }
        ensure_unique_strings(
            &case.requirement_ids,
            "web3_qualification_matrix.case.requirement_ids",
        )?;
    }
    Ok(())
}