Skip to main content

cortex_verifier/
state.rs

1//! `VerifiedTrustState` — the output of the trusted-evidence reducer.
2
3use cortex_core::ClaimCeiling;
4use serde::{Deserialize, Serialize};
5
6use crate::witness::WitnessSummary;
7
8/// Failing edge for `VerifiedTrustState::Broken`. `invariant` is a stable
9/// string from [`crate::invariant`]; `detail` is a human-readable explanation
10/// for operators and logs.
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12pub struct BrokenEdge {
13    /// Stable invariant name (e.g. `verifier.witness.disagreement`).
14    pub invariant: String,
15    /// Operator-readable detail string.
16    pub detail: String,
17}
18
19impl BrokenEdge {
20    /// Construct a `BrokenEdge` with a stable invariant name and a detail string.
21    #[must_use]
22    pub fn new(invariant: &'static str, detail: impl Into<String>) -> Self {
23        Self {
24            invariant: invariant.to_string(),
25            detail: detail.into(),
26        }
27    }
28}
29
30/// One of three outcomes per ADR 0041 §"Stable failure taxonomy".
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(tag = "state", rename_all = "snake_case")]
33pub enum VerifiedTrustState {
34    /// Every required witness class is present, disjoint, fresh, well-tiered,
35    /// and signature-valid. The verifier promotes the claim to the given
36    /// effective ceiling.
37    FullChainVerified {
38        /// Effective ceiling the claim is allowed at.
39        ceiling: ClaimCeiling,
40        /// Summary of every witness that contributed.
41        witnesses: Vec<WitnessSummary>,
42    },
43    /// Some required witness class is missing or insufficient, but no edge
44    /// outright failed. Advisory-only; cannot promote.
45    Partial {
46        /// Per-axis reasons the partial result was emitted.
47        reasons: Vec<String>,
48        /// Summary of every witness that did pass.
49        witnesses: Vec<WitnessSummary>,
50    },
51    /// A required axis outright failed (digest mismatch, stale, domain overlap,
52    /// signature invalid, ceiling below required, policy fail-closed).
53    Broken {
54        /// Exact failing edge with stable invariant name.
55        edge: BrokenEdge,
56        /// Summary of every witness that was supplied. Useful for diagnosis.
57        witnesses: Vec<WitnessSummary>,
58    },
59}
60
61impl VerifiedTrustState {
62    /// True iff this is `FullChainVerified`.
63    #[must_use]
64    pub const fn is_full_chain_verified(&self) -> bool {
65        matches!(self, Self::FullChainVerified { .. })
66    }
67
68    /// True iff this is `Broken { .. }`.
69    #[must_use]
70    pub const fn is_broken(&self) -> bool {
71        matches!(self, Self::Broken { .. })
72    }
73
74    /// True iff this is `Partial { .. }`.
75    #[must_use]
76    pub const fn is_partial(&self) -> bool {
77        matches!(self, Self::Partial { .. })
78    }
79
80    /// Stable wire string for the variant (`full_chain_verified`, `partial`,
81    /// or `broken`).
82    #[must_use]
83    pub const fn wire_str(&self) -> &'static str {
84        match self {
85            Self::FullChainVerified { .. } => "full_chain_verified",
86            Self::Partial { .. } => "partial",
87            Self::Broken { .. } => "broken",
88        }
89    }
90}