exochain-consensus 0.2.0-beta

EXOCHAIN constitutional trust fabric — consensus proofs and model quorum coordination
Documentation
// Copyright 2026 Exochain Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

use exo_core::{
    hash::hash_structured,
    types::{Hash256, Timestamp},
};
use serde::{Deserialize, Serialize};

use crate::{
    error::{ConsensusError, Result},
    report::MinorityReport,
    round::DeliberationRound,
};

/// The final result of a deliberation session.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeliberationResult {
    pub session_id: String,
    pub question: String,
    pub rounds: Vec<DeliberationRound>,
    pub final_consensus: String,
    pub minority_reports: Vec<MinorityReport>,
    pub panel_confidence_index_bps: u64,
    pub rounds_to_convergence: u32,
    pub devil_advocate_summary: Option<String>,
    pub deliberation_hash: Hash256,
    pub completed_at: Timestamp,
}

impl DeliberationResult {
    pub fn compute_hash(&self) -> Result<Hash256> {
        hash_result(self)
    }
}

pub fn hash_result(result: &DeliberationResult) -> Result<Hash256> {
    #[derive(Serialize)]
    struct HashInput<'a> {
        pub domain: &'static str,
        pub schema_version: &'static str,
        pub session_id: &'a str,
        pub question: &'a str,
        pub rounds: &'a [DeliberationRound],
        pub final_consensus: &'a str,
        pub minority_reports: &'a [MinorityReport],
        pub panel_confidence_index_bps: u64,
        pub rounds_to_convergence: u32,
        pub devil_advocate_summary: &'a Option<String>,
        pub completed_at: Timestamp,
    }

    let input = HashInput {
        domain: "exo.consensus.deliberation_result.v1",
        schema_version: "1",
        session_id: &result.session_id,
        question: &result.question,
        rounds: &result.rounds,
        final_consensus: &result.final_consensus,
        minority_reports: &result.minority_reports,
        panel_confidence_index_bps: result.panel_confidence_index_bps,
        rounds_to_convergence: result.rounds_to_convergence,
        devil_advocate_summary: &result.devil_advocate_summary,
        completed_at: result.completed_at,
    };

    hash_structured(&input).map_err(|source| ConsensusError::HashSerialization {
        context: "deliberation result",
        source,
    })
}