chio-governance 0.1.2

Chio generic governance charters and case evaluation
Documentation
use crate::generic::{
    GenericGovernanceCaseArtifact, GenericGovernanceCaseEvaluation,
    GenericGovernanceCaseEvaluationRequest, GenericGovernanceCaseKind, GenericGovernanceCaseState,
    GenericGovernanceEffectiveState, GenericGovernanceFinding, GenericGovernanceFindingCode,
};
use crate::listing::normalize_namespace;

pub fn evaluate_generic_governance_case(
    request: &GenericGovernanceCaseEvaluationRequest,
    now: u64,
) -> Result<GenericGovernanceCaseEvaluation, String> {
    request.validate()?;
    let evaluated_at = request.evaluated_at.unwrap_or(now);

    if !request
        .listing
        .verify_signature()
        .map_err(|error| error.to_string())?
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::ListingUnverifiable,
            "listing signature is invalid",
        ));
    }
    if !request
        .charter
        .verify_signature()
        .map_err(|error| error.to_string())?
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CharterUnverifiable,
            "governance charter signature is invalid",
        ));
    }
    if let Err(error) = request.charter.body.validate() {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CharterUnverifiable,
            &error,
        ));
    }
    if !request
        .case
        .verify_signature()
        .map_err(|error| error.to_string())?
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CaseUnverifiable,
            "governance case signature is invalid",
        ));
    }
    if let Err(error) = request.case.body.validate() {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CaseUnverifiable,
            &error,
        ));
    }
    if let Some(activation) = request.activation.as_ref() {
        if !activation
            .verify_signature()
            .map_err(|error| error.to_string())?
        {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::ActivationUnverifiable,
                "trust activation signature is invalid",
            ));
        }
        if let Err(error) = activation.body.validate() {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::ActivationUnverifiable,
                &error,
            ));
        }
    }
    if let Some(prior_case) = request.prior_case.as_ref() {
        if !prior_case
            .verify_signature()
            .map_err(|error| error.to_string())?
        {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::PriorCaseUnverifiable,
                "prior governance case signature is invalid",
            ));
        }
        if let Err(error) = prior_case.body.validate() {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::PriorCaseUnverifiable,
                &error,
            ));
        }
    }
    if let Some(activation) = request.activation.as_ref() {
        if activation.body.local_operator_id != request.charter.body.governing_operator_id {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::ActivationMismatch,
                "governance cases require a trust activation issued by the governing operator",
            ));
        }
    }

    let charter = &request.charter.body;
    let case = &request.case.body;
    let listing = &request.listing.body;
    let namespace = normalize_namespace(&listing.namespace);

    if charter.governing_operator_id != case.governing_operator_id
        || charter.charter_id != case.charter_id
        || normalize_namespace(&charter.authority_scope.namespace) != namespace
        || normalize_namespace(&case.namespace) != namespace
        || case.listing_id != listing.listing_id
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CaseMismatch,
            "governance charter or case does not match the current listing identity or namespace",
        ));
    }

    if charter
        .expires_at
        .is_some_and(|expires_at| expires_at <= evaluated_at)
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CharterExpired,
            "governance charter has expired",
        ));
    }
    if case
        .expires_at
        .is_some_and(|expires_at| expires_at <= evaluated_at)
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CaseExpired,
            "governance case has expired",
        ));
    }
    if !charter.allowed_case_kinds.contains(&case.kind) {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CharterKindUnsupported,
            "governance charter does not authorize this case kind",
        ));
    }
    if !charter
        .authority_scope
        .allowed_listing_operator_ids
        .is_empty()
        && !charter
            .authority_scope
            .allowed_listing_operator_ids
            .contains(&request.current_publisher.operator_id)
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CharterScopeMismatch,
            "current listing publisher falls outside the charter authority scope",
        ));
    }
    if !charter.authority_scope.allowed_actor_kinds.is_empty()
        && !charter
            .authority_scope
            .allowed_actor_kinds
            .contains(&listing.subject.actor_kind)
    {
        return Ok(governance_failure(
            request,
            evaluated_at,
            GenericGovernanceFindingCode::CharterScopeMismatch,
            "listing actor kind falls outside the charter authority scope",
        ));
    }

    if matches!(
        case.kind,
        GenericGovernanceCaseKind::Freeze | GenericGovernanceCaseKind::Sanction
    ) {
        let Some(activation) = request.activation.as_ref() else {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::MissingActivation,
                "freeze or sanction cases require an explicit local trust activation",
            ));
        };
        if case.activation_id.as_deref() != Some(activation.body.activation_id.as_str()) {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::ActivationMismatch,
                "governance case activation does not match the provided trust activation",
            ));
        }
    }

    if let Some(supersedes_case_id) = case.supersedes_case_id.as_deref() {
        let Some(prior_case) = request.prior_case.as_ref() else {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::SupersessionTargetMissing,
                "superseding governance case requires prior_case",
            ));
        };
        if prior_case.body.case_id != supersedes_case_id
            || normalize_namespace(&prior_case.body.namespace) != namespace
            || prior_case.body.listing_id != listing.listing_id
        {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::SupersessionTargetInvalid,
                "supersession target does not match the referenced prior governance case",
            ));
        }
    }

    if matches!(case.kind, GenericGovernanceCaseKind::Appeal) {
        let Some(appeal_of_case_id) = case.appeal_of_case_id.as_deref() else {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::AppealTargetMissing,
                "appeal case requires appeal_of_case_id",
            ));
        };
        let Some(prior_case) = request.prior_case.as_ref() else {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::AppealTargetMissing,
                "appeal case requires prior_case",
            ));
        };
        if prior_case.body.case_id != appeal_of_case_id
            || normalize_namespace(&prior_case.body.namespace) != namespace
            || prior_case.body.listing_id != listing.listing_id
            || matches!(prior_case.body.kind, GenericGovernanceCaseKind::Appeal)
        {
            return Ok(governance_failure(
                request,
                evaluated_at,
                GenericGovernanceFindingCode::AppealTargetInvalid,
                "appeal target does not match a valid prior governance case",
            ));
        }
    }

    let (effective_state, blocks_admission) = effective_state_for_case(case);
    Ok(GenericGovernanceCaseEvaluation {
        listing_id: listing.listing_id.clone(),
        namespace,
        charter_id: charter.charter_id.clone(),
        case_id: case.case_id.clone(),
        governing_operator_id: case.governing_operator_id.clone(),
        kind: case.kind,
        state: case.state,
        effective_state,
        evaluated_at,
        blocks_admission,
        findings: Vec::new(),
    })
}

pub(crate) fn effective_state_for_case(
    case: &GenericGovernanceCaseArtifact,
) -> (GenericGovernanceEffectiveState, bool) {
    match case.state {
        GenericGovernanceCaseState::Resolved
        | GenericGovernanceCaseState::Denied
        | GenericGovernanceCaseState::Superseded => (GenericGovernanceEffectiveState::Clear, false),
        GenericGovernanceCaseState::Open | GenericGovernanceCaseState::Escalated => match case.kind
        {
            GenericGovernanceCaseKind::Dispute => {
                (GenericGovernanceEffectiveState::Disputed, false)
            }
            GenericGovernanceCaseKind::Appeal => (GenericGovernanceEffectiveState::Appealed, false),
            GenericGovernanceCaseKind::Freeze => (GenericGovernanceEffectiveState::Frozen, false),
            GenericGovernanceCaseKind::Sanction => {
                (GenericGovernanceEffectiveState::Sanctioned, false)
            }
        },
        GenericGovernanceCaseState::Enforced => match case.kind {
            GenericGovernanceCaseKind::Dispute => {
                (GenericGovernanceEffectiveState::Disputed, false)
            }
            GenericGovernanceCaseKind::Appeal => (GenericGovernanceEffectiveState::Appealed, false),
            GenericGovernanceCaseKind::Freeze => (GenericGovernanceEffectiveState::Frozen, true),
            GenericGovernanceCaseKind::Sanction => {
                (GenericGovernanceEffectiveState::Sanctioned, true)
            }
        },
    }
}

pub(crate) fn governance_failure(
    request: &GenericGovernanceCaseEvaluationRequest,
    evaluated_at: u64,
    code: GenericGovernanceFindingCode,
    message: &str,
) -> GenericGovernanceCaseEvaluation {
    GenericGovernanceCaseEvaluation {
        listing_id: request.listing.body.listing_id.clone(),
        namespace: request.listing.body.namespace.clone(),
        charter_id: request.case.body.charter_id.clone(),
        case_id: request.case.body.case_id.clone(),
        governing_operator_id: request.case.body.governing_operator_id.clone(),
        kind: request.case.body.kind,
        state: request.case.body.state,
        effective_state: GenericGovernanceEffectiveState::Clear,
        evaluated_at,
        blocks_admission: false,
        findings: vec![GenericGovernanceFinding {
            code,
            message: message.to_string(),
        }],
    }
}