use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum RiskClass {
ReadOnly,
Low,
Medium,
High,
}
impl RiskClass {
pub fn is_hot_path_eligible(&self) -> bool {
matches!(self, RiskClass::ReadOnly | RiskClass::Low)
}
pub fn is_warm_path_eligible(&self) -> bool {
matches!(
self,
RiskClass::ReadOnly | RiskClass::Low | RiskClass::Medium
)
}
pub fn required_path(&self) -> ExecutionPath {
match self {
RiskClass::ReadOnly => ExecutionPath::Hot,
RiskClass::Low => ExecutionPath::Hot,
RiskClass::Medium => ExecutionPath::Warm,
RiskClass::High => ExecutionPath::Cold,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ExecutionPath {
Hot,
Warm,
Cold,
}
impl ExecutionPath {
pub fn max_ticks(&self) -> usize {
match self {
ExecutionPath::Hot => 8,
ExecutionPath::Warm => 100,
ExecutionPath::Cold => usize::MAX,
}
}
pub fn can_fit(&self, ticks: usize) -> bool {
ticks <= self.max_ticks()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum MutationClass {
ImmutableRead,
SnapshotWrite,
OntologyMutate,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DoctrineAligned;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Action<R: Copy + Eq + 'static, const TICKS: usize, M: Copy + Eq + 'static> {
pub id: String,
pub description: String,
risk: PhantomData<R>,
mutation: PhantomData<M>,
metadata: ActionMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionMetadata {
pub created_at: u64,
pub risk_class: RiskClass,
pub mutation_class: MutationClass,
pub tick_budget: usize,
pub ticks_consumed: Option<usize>,
pub in_flight: bool,
pub doctrine_distance_band: DoctrineDistanceBand,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum DoctrineDistanceBand {
Perfect,
Good,
Acceptable,
Marginal,
Unacceptable,
}
impl DoctrineDistanceBand {
pub fn min_distance(&self) -> f64 {
match self {
DoctrineDistanceBand::Perfect => 0.0,
DoctrineDistanceBand::Good => 20.0,
DoctrineDistanceBand::Acceptable => 40.0,
DoctrineDistanceBand::Marginal => 60.0,
DoctrineDistanceBand::Unacceptable => 80.0,
}
}
pub fn from_distance(distance: f64) -> Self {
match distance {
d if d < 20.0 => DoctrineDistanceBand::Perfect,
d if d < 40.0 => DoctrineDistanceBand::Good,
d if d < 60.0 => DoctrineDistanceBand::Acceptable,
d if d < 80.0 => DoctrineDistanceBand::Marginal,
_ => DoctrineDistanceBand::Unacceptable,
}
}
pub fn is_executable(&self) -> bool {
!matches!(self, DoctrineDistanceBand::Unacceptable)
}
}
pub struct ReadOnlyActionBuilder;
impl ReadOnlyActionBuilder {
pub fn create(
id: impl Into<String>, description: impl Into<String>,
) -> Action<ReadOnlyMarker, 0, ImmutableReadMarker> {
Action {
id: id.into(),
description: description.into(),
risk: PhantomData,
mutation: PhantomData,
metadata: ActionMetadata {
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
risk_class: RiskClass::ReadOnly,
mutation_class: MutationClass::ImmutableRead,
tick_budget: 0,
ticks_consumed: None,
in_flight: false,
doctrine_distance_band: DoctrineDistanceBand::Perfect,
},
}
}
}
pub struct LowRiskActionBuilder;
impl LowRiskActionBuilder {
pub fn create<const TICKS: usize>(
id: impl Into<String>, description: impl Into<String>,
) -> Result<Action<LowRiskMarker, TICKS, SnapshotWriteMarker>, String>
where
[(); TICKS]:,
{
if TICKS > 6 {
return Err(format!(
"Low-risk action budget {} exceeds hot path max of 6 ticks",
TICKS
));
}
Ok(Action {
id: id.into(),
description: description.into(),
risk: PhantomData,
mutation: PhantomData,
metadata: ActionMetadata {
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
risk_class: RiskClass::Low,
mutation_class: MutationClass::SnapshotWrite,
tick_budget: TICKS,
ticks_consumed: None,
in_flight: false,
doctrine_distance_band: DoctrineDistanceBand::Good,
},
})
}
}
pub struct MediumRiskActionBuilder;
impl MediumRiskActionBuilder {
pub fn create<const TICKS: usize>(
id: impl Into<String>, description: impl Into<String>,
) -> Result<Action<MediumRiskMarker, TICKS, SnapshotWriteMarker>, String>
where
[(); TICKS]:,
{
if TICKS > 100 {
return Err(format!(
"Medium-risk action budget {} exceeds warm path max of 100 ticks",
TICKS
));
}
Ok(Action {
id: id.into(),
description: description.into(),
risk: PhantomData,
mutation: PhantomData,
metadata: ActionMetadata {
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
risk_class: RiskClass::Medium,
mutation_class: MutationClass::SnapshotWrite,
tick_budget: TICKS,
ticks_consumed: None,
in_flight: false,
doctrine_distance_band: DoctrineDistanceBand::Acceptable,
},
})
}
}
pub struct HighRiskActionBuilder;
impl HighRiskActionBuilder {
pub fn create_with_proof<const TICKS: usize, P: DoctrineProof>(
id: impl Into<String>, description: impl Into<String>, _proof: &P,
) -> Result<Action<HighRiskMarker, TICKS, OntologyMutateMarker>, String> {
Ok(Action {
id: id.into(),
description: description.into(),
risk: PhantomData,
mutation: PhantomData,
metadata: ActionMetadata {
created_at: std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
risk_class: RiskClass::High,
mutation_class: MutationClass::OntologyMutate,
tick_budget: TICKS,
ticks_consumed: None,
in_flight: false,
doctrine_distance_band: P::doctrine_distance_band(),
},
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ReadOnlyMarker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct LowRiskMarker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MediumRiskMarker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HighRiskMarker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ImmutableReadMarker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SnapshotWriteMarker;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct OntologyMutateMarker;
pub trait DoctrineProof: Send + Sync {
fn doctrine_distance_band() -> DoctrineDistanceBand;
fn is_valid(&self) -> bool;
fn justification(&self) -> String;
}
#[derive(Debug, Clone)]
pub struct WeakProof {
#[allow(dead_code)]
proof_id: String,
}
impl WeakProof {
pub fn new(proof_id: impl Into<String>) -> Self {
Self {
proof_id: proof_id.into(),
}
}
}
impl DoctrineProof for WeakProof {
fn doctrine_distance_band() -> DoctrineDistanceBand {
DoctrineDistanceBand::Good
}
fn is_valid(&self) -> bool {
true }
fn justification(&self) -> String {
"Weak proof: basic doctrine alignment".to_string()
}
}
#[derive(Debug, Clone)]
pub struct StandardProof {
#[allow(dead_code)]
proof_id: String,
doctrine_checks_passed: usize,
}
impl StandardProof {
pub fn new(proof_id: impl Into<String>) -> Self {
Self {
proof_id: proof_id.into(),
doctrine_checks_passed: 0,
}
}
}
impl DoctrineProof for StandardProof {
fn doctrine_distance_band() -> DoctrineDistanceBand {
DoctrineDistanceBand::Acceptable
}
fn is_valid(&self) -> bool {
self.doctrine_checks_passed > 0
}
fn justification(&self) -> String {
format!(
"Standard proof: {} doctrine checks passed",
self.doctrine_checks_passed
)
}
}
#[derive(Debug, Clone)]
pub struct StrongProof {
#[allow(dead_code)]
proof_id: String,
doctrine_distance: f64,
tests_passed: usize,
}
impl StrongProof {
pub fn new(proof_id: impl Into<String>, doctrine_distance: f64) -> Self {
Self {
proof_id: proof_id.into(),
doctrine_distance,
tests_passed: 0,
}
}
}
impl DoctrineProof for StrongProof {
fn doctrine_distance_band() -> DoctrineDistanceBand {
DoctrineDistanceBand::from_distance(60.0) }
fn is_valid(&self) -> bool {
self.doctrine_distance < 75.0 && self.tests_passed > 0
}
fn justification(&self) -> String {
format!(
"Strong proof: doctrine_distance={}, {} tests passed",
self.doctrine_distance, self.tests_passed
)
}
}
pub trait HotPathEligible: Sized {
fn execute_hot_path(&self) -> Result<(), String>;
}
impl<const TICKS: usize> HotPathEligible for Action<ReadOnlyMarker, TICKS, ImmutableReadMarker> {
fn execute_hot_path(&self) -> Result<(), String> {
Ok(()) }
}
impl<const TICKS: usize> HotPathEligible for Action<LowRiskMarker, TICKS, SnapshotWriteMarker> {
fn execute_hot_path(&self) -> Result<(), String> {
if TICKS <= 6 {
Ok(())
} else {
Err(format!(
"Low-risk action with {} ticks exceeds hot path budget of 6",
TICKS
))
}
}
}
pub trait WarmPathEligible: Sized {
fn execute_warm_path(&self) -> Result<(), String>;
}
impl<const TICKS: usize> WarmPathEligible for Action<ReadOnlyMarker, TICKS, ImmutableReadMarker> {
fn execute_warm_path(&self) -> Result<(), String> {
Ok(())
}
}
impl<const TICKS: usize> WarmPathEligible for Action<LowRiskMarker, TICKS, SnapshotWriteMarker> {
fn execute_warm_path(&self) -> Result<(), String> {
Ok(())
}
}
impl<const TICKS: usize> WarmPathEligible for Action<MediumRiskMarker, TICKS, SnapshotWriteMarker> {
fn execute_warm_path(&self) -> Result<(), String> {
if TICKS <= 100 {
Ok(())
} else {
Err(format!(
"Medium-risk action with {} ticks exceeds warm path budget of 100",
TICKS
))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_readonly_action_creation() {
let _action = ReadOnlyActionBuilder::create("test-readonly", "Read-only test action");
}
#[test]
fn test_low_risk_action() {
let action = LowRiskActionBuilder::create::<4>("test-low-risk", "Low-risk 4-tick action");
assert!(action.is_ok());
let over_budget =
LowRiskActionBuilder::create::<8>("test-over-budget", "This exceeds 6-tick limit");
assert!(over_budget.is_err());
}
#[test]
fn test_medium_risk_action() {
let action =
MediumRiskActionBuilder::create::<50>("test-medium", "Medium-risk 50-tick action");
assert!(action.is_ok());
let over_budget =
MediumRiskActionBuilder::create::<150>("test-over", "Over 100-tick limit");
assert!(over_budget.is_err());
}
#[test]
fn test_high_risk_action_requires_proof() {
let proof = StrongProof::new("proof-1", 50.0);
let action = HighRiskActionBuilder::create_with_proof::<1000, StrongProof>(
"test-high-risk",
"High-risk ontology mutation",
&proof,
);
assert!(action.is_ok());
}
#[test]
fn test_doctrine_distance_bands() {
assert_eq!(
DoctrineDistanceBand::from_distance(15.0),
DoctrineDistanceBand::Perfect
);
assert_eq!(
DoctrineDistanceBand::from_distance(30.0),
DoctrineDistanceBand::Good
);
assert_eq!(
DoctrineDistanceBand::from_distance(90.0),
DoctrineDistanceBand::Unacceptable
);
}
#[test]
fn test_execution_path_constraints() {
assert_eq!(ExecutionPath::Hot.max_ticks(), 8);
assert_eq!(ExecutionPath::Warm.max_ticks(), 100);
assert!(ExecutionPath::Hot.can_fit(5));
assert!(!ExecutionPath::Hot.can_fit(10));
}
}