#![cfg_attr(coverage_nightly, coverage(off))]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridAgentSpec {
pub deterministic_core: CoreSpec,
pub probabilistic_wrapper: WrapperSpec,
pub boundary: BoundarySpec,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoreSpec {
pub verification_method: VerificationMethod,
pub max_complexity: u32,
pub invariants: Vec<Invariant>,
}
impl CoreSpec {
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Self {
Self {
verification_method: VerificationMethod::PropertyTests,
max_complexity: 10,
invariants: Vec::new(),
}
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn verification_method(mut self, method: VerificationMethod) -> Self {
self.verification_method = method;
self
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn max_complexity(mut self, complexity: u32) -> Self {
self.max_complexity = complexity;
self
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn add_invariant(mut self, invariant: Invariant) -> Self {
self.invariants.push(invariant);
self
}
}
impl Default for CoreSpec {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WrapperSpec {
pub model_type: ModelType,
pub fallback_strategy: FallbackStrategy,
pub confidence_threshold: f64,
}
impl WrapperSpec {
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Self {
Self {
model_type: ModelType::GPT4,
fallback_strategy: FallbackStrategy::Deterministic,
confidence_threshold: 0.95,
}
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn model_type(mut self, model: ModelType) -> Self {
self.model_type = model;
self
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn fallback_strategy(mut self, strategy: FallbackStrategy) -> Self {
self.fallback_strategy = strategy;
self
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn confidence_threshold(mut self, threshold: f64) -> Self {
self.confidence_threshold = threshold;
self
}
}
impl Default for WrapperSpec {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BoundarySpec {
pub serialization: SerializationFormat,
pub validation: ValidationStrategy,
pub error_propagation: ErrorPropagation,
}
impl Default for BoundarySpec {
fn default() -> Self {
Self {
serialization: SerializationFormat::JSON,
validation: ValidationStrategy::Both,
error_propagation: ErrorPropagation::Immediate,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VerificationMethod {
PropertyTests,
FormalProof,
ModelChecking,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ModelType {
GPT4,
Claude,
Local(String),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum FallbackStrategy {
Deterministic,
DefaultValue,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SerializationFormat {
JSON,
MessagePack,
Protobuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ValidationStrategy {
Schema,
Runtime,
Both,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ErrorPropagation {
Immediate,
Deferred,
Logged,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Invariant {
pub name: String,
pub description: String,
pub severity: InvariantSeverity,
}
impl Invariant {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
Self {
name: name.into(),
description: description.into(),
severity: InvariantSeverity::Error,
}
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn with_severity(mut self, severity: InvariantSeverity) -> Self {
self.severity = severity;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InvariantSeverity {
Warning,
Error,
Critical,
}
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn validate_complexity_for_quality(
spec: &CoreSpec,
quality: crate::scaffold::QualityLevel,
) -> bool {
spec.max_complexity <= quality.max_complexity()
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_core_spec_builder() {
let spec = CoreSpec::new()
.verification_method(VerificationMethod::FormalProof)
.max_complexity(5)
.add_invariant(Invariant::new("test", "Test invariant"));
assert!(matches!(
spec.verification_method,
VerificationMethod::FormalProof
));
assert_eq!(spec.max_complexity, 5);
assert_eq!(spec.invariants.len(), 1);
}
#[test]
fn test_wrapper_spec_builder() {
let spec = WrapperSpec::new()
.model_type(ModelType::Claude)
.fallback_strategy(FallbackStrategy::Error)
.confidence_threshold(0.9);
assert!(matches!(spec.model_type, ModelType::Claude));
assert!(matches!(spec.fallback_strategy, FallbackStrategy::Error));
assert_eq!(spec.confidence_threshold, 0.9);
}
#[test]
fn test_hybrid_spec_serialization() {
let spec = HybridAgentSpec {
deterministic_core: CoreSpec::default(),
probabilistic_wrapper: WrapperSpec::default(),
boundary: BoundarySpec::default(),
};
let json = serde_json::to_string(&spec).unwrap();
let deserialized: HybridAgentSpec = serde_json::from_str(&json).unwrap();
assert_eq!(
deserialized.deterministic_core.max_complexity,
spec.deterministic_core.max_complexity
);
}
#[test]
fn test_validate_complexity() {
let spec = CoreSpec::new().max_complexity(8);
assert!(validate_complexity_for_quality(
&spec,
crate::scaffold::QualityLevel::Extreme
));
let spec = CoreSpec::new().max_complexity(15);
assert!(!validate_complexity_for_quality(
&spec,
crate::scaffold::QualityLevel::Extreme
));
}
use crate::scaffold::QualityLevel;
#[test]
fn test_core_spec_new_initial_state() {
let spec = CoreSpec::new();
assert!(matches!(
spec.verification_method,
VerificationMethod::PropertyTests
));
assert_eq!(spec.max_complexity, 10);
assert!(spec.invariants.is_empty());
}
#[test]
fn test_core_spec_default_delegates_to_new() {
let a = CoreSpec::default();
let b = CoreSpec::new();
assert_eq!(a.max_complexity, b.max_complexity);
assert_eq!(a.invariants.len(), b.invariants.len());
assert!(matches!(
a.verification_method,
VerificationMethod::PropertyTests
));
}
#[test]
fn test_core_spec_verification_method_model_checking_variant() {
let spec = CoreSpec::new().verification_method(VerificationMethod::ModelChecking);
assert!(matches!(
spec.verification_method,
VerificationMethod::ModelChecking
));
}
#[test]
fn test_core_spec_add_invariant_appends() {
let spec = CoreSpec::new()
.add_invariant(Invariant::new("a", "A"))
.add_invariant(Invariant::new("b", "B"))
.add_invariant(Invariant::new("c", "C"));
assert_eq!(spec.invariants.len(), 3);
assert_eq!(spec.invariants[0].name, "a");
assert_eq!(spec.invariants[2].name, "c");
}
#[test]
fn test_wrapper_spec_new_initial_state() {
let spec = WrapperSpec::new();
assert_eq!(spec.model_type, ModelType::GPT4);
assert_eq!(spec.fallback_strategy, FallbackStrategy::Deterministic);
assert_eq!(spec.confidence_threshold, 0.95);
}
#[test]
fn test_wrapper_spec_default_delegates_to_new() {
let a = WrapperSpec::default();
let b = WrapperSpec::new();
assert_eq!(a.model_type, b.model_type);
assert_eq!(a.fallback_strategy, b.fallback_strategy);
assert_eq!(a.confidence_threshold, b.confidence_threshold);
}
#[test]
fn test_wrapper_spec_model_type_local_variant() {
let spec = WrapperSpec::new().model_type(ModelType::Local("/models/m.gguf".to_string()));
match &spec.model_type {
ModelType::Local(p) => assert_eq!(p, "/models/m.gguf"),
other => panic!("expected Local, got {other:?}"),
}
}
#[test]
fn test_wrapper_spec_fallback_default_value_variant() {
let spec = WrapperSpec::new().fallback_strategy(FallbackStrategy::DefaultValue);
assert_eq!(spec.fallback_strategy, FallbackStrategy::DefaultValue);
}
#[test]
fn test_boundary_spec_default_fields() {
let b = BoundarySpec::default();
assert!(matches!(b.serialization, SerializationFormat::JSON));
assert!(matches!(b.validation, ValidationStrategy::Both));
assert!(matches!(b.error_propagation, ErrorPropagation::Immediate));
}
#[test]
fn test_invariant_default_severity_is_error() {
let inv = Invariant::new("x", "X");
assert!(matches!(inv.severity, InvariantSeverity::Error));
}
#[test]
fn test_invariant_with_severity_sets_all_variants() {
for sev in [
InvariantSeverity::Warning,
InvariantSeverity::Error,
InvariantSeverity::Critical,
] {
let inv = Invariant::new("x", "X").with_severity(sev.clone());
match (&inv.severity, &sev) {
(InvariantSeverity::Warning, InvariantSeverity::Warning)
| (InvariantSeverity::Error, InvariantSeverity::Error)
| (InvariantSeverity::Critical, InvariantSeverity::Critical) => {}
_ => panic!("severity mismatch after with_severity"),
}
}
}
#[test]
fn test_validate_complexity_standard_boundary() {
assert!(validate_complexity_for_quality(
&CoreSpec::new().max_complexity(20),
QualityLevel::Standard
));
assert!(!validate_complexity_for_quality(
&CoreSpec::new().max_complexity(21),
QualityLevel::Standard
));
}
#[test]
fn test_validate_complexity_strict_boundary() {
assert!(validate_complexity_for_quality(
&CoreSpec::new().max_complexity(15),
QualityLevel::Strict
));
assert!(!validate_complexity_for_quality(
&CoreSpec::new().max_complexity(16),
QualityLevel::Strict
));
}
#[test]
fn test_validate_complexity_extreme_boundary() {
assert!(validate_complexity_for_quality(
&CoreSpec::new().max_complexity(10),
QualityLevel::Extreme
));
assert!(!validate_complexity_for_quality(
&CoreSpec::new().max_complexity(11),
QualityLevel::Extreme
));
}
#[test]
fn test_serialization_format_variants_round_trip() {
for fmt in [
SerializationFormat::JSON,
SerializationFormat::MessagePack,
SerializationFormat::Protobuf,
] {
let s = serde_json::to_string(&fmt).expect("serialize");
let back: SerializationFormat = serde_json::from_str(&s).expect("deserialize");
let s2 = serde_json::to_string(&back).expect("re-serialize");
assert_eq!(s, s2);
}
}
#[test]
fn test_validation_strategy_variants_round_trip() {
for v in [
ValidationStrategy::Schema,
ValidationStrategy::Runtime,
ValidationStrategy::Both,
] {
let s = serde_json::to_string(&v).expect("serialize");
let back: ValidationStrategy = serde_json::from_str(&s).expect("deserialize");
let s2 = serde_json::to_string(&back).expect("re-serialize");
assert_eq!(s, s2);
}
}
#[test]
fn test_error_propagation_variants_round_trip() {
for v in [
ErrorPropagation::Immediate,
ErrorPropagation::Deferred,
ErrorPropagation::Logged,
] {
let s = serde_json::to_string(&v).expect("serialize");
let back: ErrorPropagation = serde_json::from_str(&s).expect("deserialize");
let s2 = serde_json::to_string(&back).expect("re-serialize");
assert_eq!(s, s2);
}
}
#[test]
fn test_hybrid_spec_serialization_with_non_default_fields() {
let spec = HybridAgentSpec {
deterministic_core: CoreSpec::new()
.verification_method(VerificationMethod::FormalProof)
.max_complexity(7)
.add_invariant(
Invariant::new("n1", "d1").with_severity(InvariantSeverity::Critical),
),
probabilistic_wrapper: WrapperSpec::new()
.model_type(ModelType::Local("/m".to_string()))
.fallback_strategy(FallbackStrategy::DefaultValue)
.confidence_threshold(0.42),
boundary: BoundarySpec {
serialization: SerializationFormat::Protobuf,
validation: ValidationStrategy::Runtime,
error_propagation: ErrorPropagation::Logged,
},
};
let json = serde_json::to_string(&spec).expect("serialize");
let back: HybridAgentSpec = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back.deterministic_core.max_complexity, 7);
assert_eq!(back.probabilistic_wrapper.confidence_threshold, 0.42);
assert_eq!(
back.probabilistic_wrapper.fallback_strategy,
FallbackStrategy::DefaultValue
);
match &back.probabilistic_wrapper.model_type {
ModelType::Local(p) => assert_eq!(p, "/m"),
other => panic!("expected Local, got {other:?}"),
}
assert!(matches!(
back.boundary.serialization,
SerializationFormat::Protobuf
));
assert!(matches!(
back.boundary.validation,
ValidationStrategy::Runtime
));
assert!(matches!(
back.boundary.error_propagation,
ErrorPropagation::Logged
));
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}