chio_web3/
qualification.rs1use std::collections::HashSet;
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::Web3ContractError;
6use crate::settlement::Web3SettlementLifecycleState;
7use crate::validation::{ensure_non_empty, ensure_unique_strings};
8
9pub const CHIO_WEB3_QUALIFICATION_MATRIX_SCHEMA: &str = "chio.web3-qualification-matrix.v1";
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13pub enum Web3QualificationOutcome {
14 Pass,
15 FailClosed,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(deny_unknown_fields)]
20pub struct Web3QualificationCase {
21 pub id: String,
22 pub name: String,
23 pub requirement_ids: Vec<String>,
24 pub lifecycle_state: Web3SettlementLifecycleState,
25 pub expected_outcome: Web3QualificationOutcome,
26 pub observed_outcome: Web3QualificationOutcome,
27 pub notes: String,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(deny_unknown_fields)]
32pub struct Web3QualificationMatrix {
33 pub schema: String,
34 pub trust_profile_id: String,
35 pub contract_package_id: String,
36 pub cases: Vec<Web3QualificationCase>,
37}
38pub fn validate_web3_qualification_matrix(
39 matrix: &Web3QualificationMatrix,
40) -> Result<(), Web3ContractError> {
41 if matrix.schema != CHIO_WEB3_QUALIFICATION_MATRIX_SCHEMA {
42 return Err(Web3ContractError::UnsupportedSchema(matrix.schema.clone()));
43 }
44 ensure_non_empty(
45 &matrix.trust_profile_id,
46 "web3_qualification_matrix.trust_profile_id",
47 )?;
48 ensure_non_empty(
49 &matrix.contract_package_id,
50 "web3_qualification_matrix.contract_package_id",
51 )?;
52 if matrix.cases.is_empty() {
53 return Err(Web3ContractError::MissingField(
54 "web3_qualification_matrix.cases",
55 ));
56 }
57 let mut case_ids = HashSet::new();
58 for case in &matrix.cases {
59 ensure_non_empty(&case.id, "web3_qualification_matrix.case.id")?;
60 ensure_non_empty(&case.name, "web3_qualification_matrix.case.name")?;
61 ensure_non_empty(&case.notes, "web3_qualification_matrix.case.notes")?;
62 if !case_ids.insert(case.id.as_str()) {
63 return Err(Web3ContractError::DuplicateValue(case.id.clone()));
64 }
65 if case.requirement_ids.is_empty() {
66 return Err(Web3ContractError::InvalidQualificationCase(format!(
67 "case {} must cite at least one requirement id",
68 case.id
69 )));
70 }
71 ensure_unique_strings(
72 &case.requirement_ids,
73 "web3_qualification_matrix.case.requirement_ids",
74 )?;
75 }
76 Ok(())
77}