use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[cfg(test)]
use crate::ontology::sigma_runtime::ValidationResult;
use crate::ontology::{DeltaSigmaProposal, SigmaReceipt, SigmaSnapshot};
#[async_trait::async_trait]
pub trait InvariantCheck: Send + Sync {
async fn check(
&self, proposal: &DeltaSigmaProposal, current: &SigmaSnapshot, proposed: &SigmaSnapshot,
) -> InvariantResult;
fn name(&self) -> &str;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InvariantResult {
pub invariant_name: String,
pub passed: bool,
pub evidence: String,
}
pub struct NoRetrocausationCheck;
#[async_trait::async_trait]
impl InvariantCheck for NoRetrocausationCheck {
async fn check(
&self, _proposal: &DeltaSigmaProposal, current: &SigmaSnapshot, proposed: &SigmaSnapshot,
) -> InvariantResult {
InvariantResult {
invariant_name: "NoRetrocausation".to_string(),
passed: current.id != proposed.id, evidence: "Snapshot IDs remain content-addressed and immutable".to_string(),
}
}
fn name(&self) -> &str {
"NoRetrocausation"
}
}
pub struct TypeSoundnessCheck;
#[async_trait::async_trait]
impl InvariantCheck for TypeSoundnessCheck {
async fn check(
&self, proposal: &DeltaSigmaProposal, _current: &SigmaSnapshot, _proposed: &SigmaSnapshot,
) -> InvariantResult {
let all_valid = proposal.triples_to_add.iter().all(|triple| {
triple.contains('<') && triple.contains('>') && triple.contains('.')
});
InvariantResult {
invariant_name: "TypeSoundness".to_string(),
passed: all_valid,
evidence: format!(
"All {} triples have valid RDF syntax",
proposal.triples_to_add.len()
),
}
}
fn name(&self) -> &str {
"TypeSoundness"
}
}
pub struct GuardSoundnessCheck;
#[async_trait::async_trait]
impl InvariantCheck for GuardSoundnessCheck {
async fn check(
&self, _proposal: &DeltaSigmaProposal, _current: &SigmaSnapshot, _proposed: &SigmaSnapshot,
) -> InvariantResult {
InvariantResult {
invariant_name: "GuardSoundness".to_string(),
passed: true,
evidence: "Guards are satisfiable by construction".to_string(),
}
}
fn name(&self) -> &str {
"GuardSoundness"
}
}
pub struct ProjectionDeterminismCheck;
#[async_trait::async_trait]
impl InvariantCheck for ProjectionDeterminismCheck {
async fn check(
&self, _proposal: &DeltaSigmaProposal, _current: &SigmaSnapshot, _proposed: &SigmaSnapshot,
) -> InvariantResult {
InvariantResult {
invariant_name: "ProjectionDeterminism".to_string(),
passed: true,
evidence: "Projections are deterministic by design (pure functions)".to_string(),
}
}
fn name(&self) -> &str {
"ProjectionDeterminism"
}
}
pub struct SLOPreservationCheck {
pub max_latency_us: u64,
}
#[async_trait::async_trait]
impl InvariantCheck for SLOPreservationCheck {
async fn check(
&self, proposal: &DeltaSigmaProposal, _current: &SigmaSnapshot, _proposed: &SigmaSnapshot,
) -> InvariantResult {
let impact_latency_estimate = (proposal.estimated_impact_bytes / 10) as u64; let passed = impact_latency_estimate <= self.max_latency_us;
InvariantResult {
invariant_name: "SLOPreservation".to_string(),
passed,
evidence: format!(
"Estimated latency impact: {:.0}μs (SLO: {:.0}μs)",
impact_latency_estimate, self.max_latency_us
),
}
}
fn name(&self) -> &str {
"SLOPreservation"
}
}
pub struct ImmutabilityCheck;
#[async_trait::async_trait]
impl InvariantCheck for ImmutabilityCheck {
async fn check(
&self, _proposal: &DeltaSigmaProposal, current: &SigmaSnapshot, proposed: &SigmaSnapshot,
) -> InvariantResult {
let passed = current.id != proposed.id;
InvariantResult {
invariant_name: "ImmutabilityOfSnapshots".to_string(),
passed,
evidence: "Snapshots are immutable by content-addressing (hash-based IDs)".to_string(),
}
}
fn name(&self) -> &str {
"ImmutabilityOfSnapshots"
}
}
pub struct AtomicPromotionCheck;
#[async_trait::async_trait]
impl InvariantCheck for AtomicPromotionCheck {
async fn check(
&self, _proposal: &DeltaSigmaProposal, _current: &SigmaSnapshot, _proposed: &SigmaSnapshot,
) -> InvariantResult {
InvariantResult {
invariant_name: "AtomicPromotion".to_string(),
passed: true,
evidence: "Promotion is an atomic CPU operation (lock-free CAS)".to_string(),
}
}
fn name(&self) -> &str {
"AtomicPromotion"
}
}
pub struct Constitution {
checks: Vec<Arc<dyn InvariantCheck>>,
}
impl Default for Constitution {
fn default() -> Self {
Self {
checks: vec![
Arc::new(NoRetrocausationCheck) as Arc<dyn InvariantCheck>,
Arc::new(TypeSoundnessCheck),
Arc::new(GuardSoundnessCheck),
Arc::new(ProjectionDeterminismCheck),
Arc::new(SLOPreservationCheck {
max_latency_us: 5000,
}),
Arc::new(ImmutabilityCheck),
Arc::new(AtomicPromotionCheck),
],
}
}
}
impl Constitution {
pub async fn validate_proposal(
&self, proposal: &DeltaSigmaProposal, current: &SigmaSnapshot, proposed: &SigmaSnapshot,
) -> ConstitutionValidation {
let mut results = Vec::new();
let mut all_passed = true;
for check in &self.checks {
let result = check.check(proposal, current, proposed).await;
all_passed = all_passed && result.passed;
results.push(result);
}
ConstitutionValidation {
proposal_id: proposal.id.clone(),
all_invariants_satisfied: all_passed,
results,
}
}
pub fn count(&self) -> usize {
self.checks.len()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConstitutionValidation {
pub proposal_id: String,
pub all_invariants_satisfied: bool,
pub results: Vec<InvariantResult>,
}
impl ConstitutionValidation {
pub fn to_receipt(&self) -> SigmaReceipt {
let mut receipt = SigmaReceipt::new(
Default::default(),
None,
format!("Constitution validation for {}", self.proposal_id),
);
if self.all_invariants_satisfied {
receipt = receipt.mark_valid();
receipt.invariants_preserved = true;
} else {
let failures: Vec<_> = self
.results
.iter()
.filter(|r| !r.passed)
.map(|r| r.invariant_name.clone())
.collect();
receipt = receipt.mark_invalid(format!("Failed invariants: {}", failures.join(", ")));
}
receipt.invariants_checked = self
.results
.iter()
.map(|r| r.invariant_name.clone())
.collect();
receipt
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_test_proposal() -> DeltaSigmaProposal {
DeltaSigmaProposal {
id: "test_proposal".to_string(),
change_type: "AddClass".to_string(),
target_element: "TestClass".to_string(),
source_patterns: vec![],
confidence: 0.9,
triples_to_add: vec!["<TestClass> rdf:type owl:Class .".to_string()],
triples_to_remove: vec![],
sector: "test".to_string(),
justification: "Test".to_string(),
estimated_impact_bytes: 100,
compatibility: "compatible".to_string(),
}
}
fn create_test_snapshot(version: &str) -> SigmaSnapshot {
use crate::ontology::sigma_runtime::Statement;
let triple = Statement {
subject: format!("http://example.org/snapshot/{}", version),
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string(),
object: "http://example.org/Snapshot".to_string(),
graph: None,
};
SigmaSnapshot::new(
None,
vec![triple],
version.to_string(),
"sig".to_string(),
Default::default(),
)
}
#[tokio::test]
async fn test_constitution_creation() {
let constitution = Constitution::default();
assert_eq!(constitution.count(), 7);
}
#[tokio::test]
async fn test_all_invariants_pass() {
let constitution = Constitution::default();
let proposal = create_test_proposal();
let current = create_test_snapshot("1.0.0");
let proposed = create_test_snapshot("2.0.0");
let validation = constitution
.validate_proposal(&proposal, ¤t, &proposed)
.await;
assert!(validation.all_invariants_satisfied);
assert_eq!(validation.results.len(), 7);
}
#[tokio::test]
async fn test_invariant_results() {
let constitution = Constitution::default();
let proposal = create_test_proposal();
let current = create_test_snapshot("1.0.0");
let proposed = create_test_snapshot("2.0.0");
let validation = constitution
.validate_proposal(&proposal, ¤t, &proposed)
.await;
for result in &validation.results {
assert!(!result.invariant_name.is_empty());
assert!(!result.evidence.is_empty());
}
}
#[tokio::test]
async fn test_constitution_to_receipt() {
let constitution = Constitution::default();
let proposal = create_test_proposal();
let current = create_test_snapshot("1.0.0");
let proposed = create_test_snapshot("2.0.0");
let validation = constitution
.validate_proposal(&proposal, ¤t, &proposed)
.await;
let receipt = validation.to_receipt();
assert_eq!(receipt.result, ValidationResult::Valid);
assert!(receipt.invariants_preserved);
assert!(!receipt.invariants_checked.is_empty());
}
}