use crate::calibration::{
Phase4Config,
feature_flags::CalibV22Config,
};
use anyhow::{Context, Result};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::HashMap;
use std::fmt;
use tracing::{info, warn};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ComponentVersion {
pub version: String,
pub git_hash: Option<String>,
pub build_timestamp: DateTime<Utc>,
pub build_features: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SbomEntry {
pub name: String,
pub version: String,
pub license: Option<String>,
pub source_url: Option<String>,
pub hash: String,
pub component_type: SbomComponentType,
pub security_scan: Option<SecurityScanResult>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum SbomComponentType {
RustLibrary,
WasmModule,
TypeScriptGlue,
ConfigurationFile,
BinaryExecutable,
ModelData,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecurityScanResult {
pub scanner: String,
pub scan_time: DateTime<Utc>,
pub high_severity_count: u32,
pub medium_severity_count: u32,
pub low_severity_count: u32,
pub security_score: f32,
pub cve_list: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConfigurationFingerprint {
pub config_hash: String,
pub rust_lib_hash: String,
pub wasm_hash: String,
pub typescript_glue_hash: String,
pub quantile_policy_hash: String,
pub float_rounding_hash: String,
pub bootstrap_settings_hash: String,
pub generated_at: DateTime<Utc>,
pub algorithm: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FloatRoundingConfig {
pub calibrated_score_precision: u8,
pub ece_precision: u8,
pub confidence_precision: u8,
pub rounding_strategy: RoundingStrategy,
pub deterministic_mode: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum RoundingStrategy {
RoundNearestEven,
RoundTowardZero,
RoundUp,
RoundDown,
BankersRounding,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct QuantilePolicyConfig {
pub ece_quantiles: Vec<f32>,
pub latency_quantiles: Vec<f32>,
pub interpolation_method: QuantileInterpolation,
pub enable_smoothing: bool,
pub smoothing_window: u32,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum QuantileInterpolation {
Linear,
Nearest,
Lower,
Higher,
Midpoint,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BootstrapConfig {
pub iterations: u32,
pub sample_ratio: f32,
pub random_seed: u64,
pub confidence_level: f32,
pub stratified_sampling: bool,
pub method: BootstrapMethod,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum BootstrapMethod {
StandardBootstrap,
BlockBootstrap { block_size: u32 },
CircularBlockBootstrap { block_size: u32 },
MovingBlockBootstrap { block_size: u32 },
StationaryBootstrap { expected_block_size: f32 },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum IntegrityStatus {
Valid,
HashMismatch { mismatched_components: Vec<String> },
VersionIncompatible { incompatible_versions: Vec<String> },
SecurityIssue { vulnerability_count: u32 },
ConfigurationInvalid { validation_errors: Vec<String> },
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CalibrationManifest {
pub manifest_version: String,
pub generated_at: DateTime<Utc>,
pub environment: String,
pub deployment_id: String,
pub component_versions: HashMap<String, ComponentVersion>,
pub compatibility_matrix: HashMap<String, Vec<String>>,
pub config_fingerprint: ConfigurationFingerprint,
pub phase4_config: Phase4Config,
pub feature_flags: CalibV22Config,
pub float_rounding: FloatRoundingConfig,
pub quantile_policy: QuantilePolicyConfig,
pub bootstrap_config: BootstrapConfig,
pub sbom: Vec<SbomEntry>,
pub sbom_tool_version: String,
pub sbom_signature: Option<String>,
pub integrity_status: IntegrityStatus,
pub validation_results: HashMap<String, ValidationResult>,
pub security_summary: SecuritySummary,
pub change_log: Vec<ConfigurationChange>,
pub approval_chain: Vec<ApprovalEntry>,
pub attestations: HashMap<String, AttestationSignature>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ValidationResult {
pub passed: bool,
pub message: String,
pub validated_at: DateTime<Utc>,
pub validator: String,
pub details: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SecuritySummary {
pub overall_score: f32,
pub total_vulnerabilities: u32,
pub high_severity_count: u32,
pub medium_severity_count: u32,
pub low_severity_count: u32,
pub last_scan: DateTime<Utc>,
pub compliance_status: ComplianceStatus,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ComplianceStatus {
Compliant,
MinorIssues { issue_count: u32 },
MajorViolations { violation_count: u32 },
Critical { critical_count: u32 },
NotScanned,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConfigurationChange {
pub timestamp: DateTime<Utc>,
pub changed_by: String,
pub description: String,
pub section: String,
pub previous_hash: Option<String>,
pub new_hash: String,
pub justification: String,
pub ticket_reference: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ApprovalEntry {
pub approver: String,
pub approved_at: DateTime<Utc>,
pub approval_level: ApprovalLevel,
pub signature: String,
pub comments: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ApprovalLevel {
Technical,
Security,
Business,
Compliance,
Emergency { override_reason: String },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttestationSignature {
pub algorithm: String,
pub signature: String,
pub key_id: String,
pub signed_at: DateTime<Utc>,
pub signer: String,
}
impl CalibrationManifest {
pub fn new(
environment: String,
deployment_id: String,
phase4_config: Phase4Config,
feature_flags: CalibV22Config,
) -> Result<Self> {
let generated_at = Utc::now();
info!("Creating calibration manifest for deployment: {}", deployment_id);
info!("Environment: {}, Generated: {}", environment, generated_at);
let float_rounding = FloatRoundingConfig::default();
let quantile_policy = QuantilePolicyConfig::default();
let bootstrap_config = BootstrapConfig::default();
let config_fingerprint = Self::generate_configuration_fingerprint(
&phase4_config,
&feature_flags,
&float_rounding,
&quantile_policy,
&bootstrap_config,
)?;
let sbom = Vec::new();
let component_versions = Self::collect_component_versions()?;
let manifest = CalibrationManifest {
manifest_version: "1.0.0".to_string(),
generated_at,
environment,
deployment_id,
component_versions,
compatibility_matrix: Self::build_compatibility_matrix(),
config_fingerprint,
phase4_config,
feature_flags,
float_rounding,
quantile_policy,
bootstrap_config,
sbom,
sbom_tool_version: "cargo-audit-0.20.0".to_string(),
sbom_signature: None,
integrity_status: IntegrityStatus::Unknown,
validation_results: HashMap::new(),
security_summary: SecuritySummary::default(),
change_log: Vec::new(),
approval_chain: Vec::new(),
attestations: HashMap::new(),
};
info!("Calibration manifest created successfully");
info!("Configuration fingerprint: {}", manifest.config_fingerprint.config_hash[..16].to_string());
Ok(manifest)
}
pub fn generate_configuration_fingerprint(
phase4_config: &Phase4Config,
feature_flags: &CalibV22Config,
float_rounding: &FloatRoundingConfig,
quantile_policy: &QuantilePolicyConfig,
bootstrap_config: &BootstrapConfig,
) -> Result<ConfigurationFingerprint> {
let generated_at = Utc::now();
let algorithm = "SHA-256".to_string();
let phase4_json = serde_json::to_string(phase4_config)
.context("Failed to serialize Phase4Config")?;
let feature_flags_json = serde_json::to_string(feature_flags)
.context("Failed to serialize CalibV22Config")?;
let float_rounding_json = serde_json::to_string(float_rounding)
.context("Failed to serialize FloatRoundingConfig")?;
let quantile_policy_json = serde_json::to_string(quantile_policy)
.context("Failed to serialize QuantilePolicyConfig")?;
let bootstrap_config_json = serde_json::to_string(bootstrap_config)
.context("Failed to serialize BootstrapConfig")?;
let rust_lib_hash = Self::sha256_hash(&phase4_json);
let wasm_hash = Self::sha256_hash("wasm-placeholder"); let typescript_glue_hash = Self::sha256_hash("typescript-placeholder"); let quantile_policy_hash = Self::sha256_hash(&quantile_policy_json);
let float_rounding_hash = Self::sha256_hash(&float_rounding_json);
let bootstrap_settings_hash = Self::sha256_hash(&bootstrap_config_json);
let config_data = format!(
"{}{}{}{}{}{}{}",
phase4_json, feature_flags_json, float_rounding_json,
quantile_policy_json, bootstrap_config_json,
rust_lib_hash, wasm_hash
);
let config_hash = Self::sha256_hash(&config_data);
Ok(ConfigurationFingerprint {
config_hash,
rust_lib_hash,
wasm_hash,
typescript_glue_hash,
quantile_policy_hash,
float_rounding_hash,
bootstrap_settings_hash,
generated_at,
algorithm,
})
}
pub fn validate_integrity(&mut self) -> Result<()> {
info!("Validating calibration manifest integrity");
let mut validation_results = HashMap::new();
let mut all_valid = true;
match self.validate_configuration_fingerprint() {
Ok(()) => {
validation_results.insert(
"configuration_fingerprint".to_string(),
ValidationResult {
passed: true,
message: "Configuration fingerprint validation passed".to_string(),
validated_at: Utc::now(),
validator: "manifest_validator".to_string(),
details: HashMap::new(),
}
);
}
Err(e) => {
all_valid = false;
validation_results.insert(
"configuration_fingerprint".to_string(),
ValidationResult {
passed: false,
message: format!("Configuration fingerprint validation failed: {}", e),
validated_at: Utc::now(),
validator: "manifest_validator".to_string(),
details: HashMap::new(),
}
);
}
}
match self.validate_phase4_config() {
Ok(()) => {
validation_results.insert(
"phase4_config".to_string(),
ValidationResult {
passed: true,
message: "Phase 4 configuration validation passed".to_string(),
validated_at: Utc::now(),
validator: "phase4_validator".to_string(),
details: HashMap::new(),
}
);
}
Err(e) => {
all_valid = false;
validation_results.insert(
"phase4_config".to_string(),
ValidationResult {
passed: false,
message: format!("Phase 4 configuration validation failed: {}", e),
validated_at: Utc::now(),
validator: "phase4_validator".to_string(),
details: HashMap::new(),
}
);
}
}
match self.validate_sbom_integrity() {
Ok(()) => {
validation_results.insert(
"sbom_integrity".to_string(),
ValidationResult {
passed: true,
message: "SBOM integrity validation passed".to_string(),
validated_at: Utc::now(),
validator: "sbom_validator".to_string(),
details: HashMap::new(),
}
);
}
Err(e) => {
all_valid = false;
validation_results.insert(
"sbom_integrity".to_string(),
ValidationResult {
passed: false,
message: format!("SBOM integrity validation failed: {}", e),
validated_at: Utc::now(),
validator: "sbom_validator".to_string(),
details: HashMap::new(),
}
);
}
}
self.validation_results = validation_results;
self.integrity_status = if all_valid {
IntegrityStatus::Valid
} else {
let failed_validations: Vec<String> = self.validation_results
.iter()
.filter(|(_, result)| !result.passed)
.map(|(key, _)| key.clone())
.collect();
IntegrityStatus::ConfigurationInvalid {
validation_errors: failed_validations,
}
};
if all_valid {
info!("✓ Manifest integrity validation passed");
} else {
warn!("âš Manifest integrity validation failed");
}
Ok(())
}
pub fn add_sbom_entry(&mut self, entry: SbomEntry) -> Result<()> {
info!("Adding SBOM entry: {} v{}", entry.name, entry.version);
if self.sbom.iter().any(|e| e.name == entry.name && e.version == entry.version) {
warn!("SBOM entry already exists: {} v{}", entry.name, entry.version);
return Ok(());
}
self.sbom.push(entry);
Ok(())
}
pub fn update_security_summary(&mut self, summary: SecuritySummary) {
info!("Updating security summary: {} vulnerabilities, score: {:.1}",
summary.total_vulnerabilities, summary.overall_score);
self.security_summary = summary;
if self.security_summary.high_severity_count > 0 {
self.integrity_status = IntegrityStatus::SecurityIssue {
vulnerability_count: self.security_summary.high_severity_count,
};
}
}
pub fn add_configuration_change(&mut self, change: ConfigurationChange) {
info!("Recording configuration change: {} by {}", change.description, change.changed_by);
self.change_log.push(change);
}
pub fn add_approval(&mut self, approval: ApprovalEntry) -> Result<()> {
info!("Adding approval: {} by {} at level {:?}",
approval.signature[..8].to_string(), approval.approver, approval.approval_level);
self.approval_chain.push(approval);
Ok(())
}
pub fn add_attestation(&mut self, component: String, signature: AttestationSignature) -> Result<()> {
info!("Adding attestation for component: {}", component);
self.attestations.insert(component, signature);
Ok(())
}
pub fn to_json(&self) -> Result<String> {
serde_json::to_string_pretty(self)
.context("Failed to serialize manifest to JSON")
}
pub fn from_json(json: &str) -> Result<Self> {
serde_json::from_str(json)
.context("Failed to deserialize manifest from JSON")
}
pub fn get_summary(&self) -> ManifestSummary {
ManifestSummary {
deployment_id: self.deployment_id.clone(),
environment: self.environment.clone(),
generated_at: self.generated_at,
config_hash: self.config_fingerprint.config_hash[..16].to_string(),
integrity_status: self.integrity_status.clone(),
component_count: self.component_versions.len(),
sbom_entry_count: self.sbom.len(),
validation_status: self.validation_results.values().all(|v| v.passed),
security_score: self.security_summary.overall_score,
approval_count: self.approval_chain.len(),
}
}
pub fn sha256_hash(data: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(data.as_bytes());
hex::encode(hasher.finalize())
}
fn collect_component_versions() -> Result<HashMap<String, ComponentVersion>> {
let mut versions = HashMap::new();
versions.insert(
"lens-core".to_string(),
ComponentVersion {
version: env!("CARGO_PKG_VERSION").to_string(),
git_hash: option_env!("GIT_HASH").map(|s| s.to_string()),
build_timestamp: Utc::now(),
build_features: vec!["default".to_string()],
}
);
Ok(versions)
}
fn build_compatibility_matrix() -> HashMap<String, Vec<String>> {
let mut matrix = HashMap::new();
matrix.insert(
"manifest_version".to_string(),
vec!["1.0.0".to_string()],
);
matrix.insert(
"phase4_config".to_string(),
vec!["1.0.0".to_string(), "1.1.0".to_string()],
);
matrix
}
fn validate_configuration_fingerprint(&self) -> Result<()> {
let expected_fingerprint = Self::generate_configuration_fingerprint(
&self.phase4_config,
&self.feature_flags,
&self.float_rounding,
&self.quantile_policy,
&self.bootstrap_config,
)?;
if self.config_fingerprint.config_hash != expected_fingerprint.config_hash {
anyhow::bail!(
"Configuration fingerprint mismatch: expected {}, got {}",
expected_fingerprint.config_hash[..16].to_string(),
self.config_fingerprint.config_hash[..16].to_string()
);
}
Ok(())
}
fn validate_phase4_config(&self) -> Result<()> {
if self.phase4_config.target_ece > 0.015 {
anyhow::bail!("Target ECE {:.4} exceeds Phase 4 requirement ≤ 0.015",
self.phase4_config.target_ece);
}
if self.phase4_config.max_language_variance >= 7.0 {
anyhow::bail!("Language variance {:.1}pp exceeds Phase 4 requirement < 7pp",
self.phase4_config.max_language_variance);
}
if self.phase4_config.isotonic_slope_clamp != (0.9, 1.1) {
anyhow::bail!("Isotonic slope clamp {:?} must be [0.9, 1.1] per specification",
self.phase4_config.isotonic_slope_clamp);
}
Ok(())
}
fn validate_sbom_integrity(&self) -> Result<()> {
for entry in &self.sbom {
if entry.hash.len() != 64 {
anyhow::bail!("Invalid hash length for SBOM entry {}: {}",
entry.name, entry.hash.len());
}
if !entry.hash.chars().all(|c| c.is_ascii_hexdigit()) {
anyhow::bail!("Invalid hash format for SBOM entry {}", entry.name);
}
}
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManifestSummary {
pub deployment_id: String,
pub environment: String,
pub generated_at: DateTime<Utc>,
pub config_hash: String,
pub integrity_status: IntegrityStatus,
pub component_count: usize,
pub sbom_entry_count: usize,
pub validation_status: bool,
pub security_score: f32,
pub approval_count: usize,
}
impl Default for FloatRoundingConfig {
fn default() -> Self {
Self {
calibrated_score_precision: 6,
ece_precision: 4,
confidence_precision: 3,
rounding_strategy: RoundingStrategy::RoundNearestEven,
deterministic_mode: true,
}
}
}
impl Default for QuantilePolicyConfig {
fn default() -> Self {
Self {
ece_quantiles: vec![0.5, 0.9, 0.95, 0.99],
latency_quantiles: vec![0.5, 0.9, 0.95, 0.99],
interpolation_method: QuantileInterpolation::Linear,
enable_smoothing: false,
smoothing_window: 10,
}
}
}
impl Default for BootstrapConfig {
fn default() -> Self {
Self {
iterations: 1000,
sample_ratio: 1.0,
random_seed: 42,
confidence_level: 0.95,
stratified_sampling: true,
method: BootstrapMethod::StandardBootstrap,
}
}
}
impl Default for SecuritySummary {
fn default() -> Self {
Self {
overall_score: 0.0,
total_vulnerabilities: 0,
high_severity_count: 0,
medium_severity_count: 0,
low_severity_count: 0,
last_scan: Utc::now(),
compliance_status: ComplianceStatus::NotScanned,
}
}
}
impl fmt::Display for IntegrityStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IntegrityStatus::Valid => write!(f, "✓ Valid"),
IntegrityStatus::HashMismatch { mismatched_components } => {
write!(f, "✗ Hash Mismatch: {}", mismatched_components.join(", "))
}
IntegrityStatus::VersionIncompatible { incompatible_versions } => {
write!(f, "✗ Version Incompatible: {}", incompatible_versions.join(", "))
}
IntegrityStatus::SecurityIssue { vulnerability_count } => {
write!(f, "âš Security Issues: {} vulnerabilities", vulnerability_count)
}
IntegrityStatus::ConfigurationInvalid { validation_errors } => {
write!(f, "✗ Configuration Invalid: {}", validation_errors.join(", "))
}
IntegrityStatus::Unknown => write!(f, "? Unknown"),
}
}
}
impl fmt::Display for ComplianceStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ComplianceStatus::Compliant => write!(f, "✓ Compliant"),
ComplianceStatus::MinorIssues { issue_count } => {
write!(f, "âš Minor Issues: {}", issue_count)
}
ComplianceStatus::MajorViolations { violation_count } => {
write!(f, "✗ Major Violations: {}", violation_count)
}
ComplianceStatus::Critical { critical_count } => {
write!(f, "🚨 Critical: {}", critical_count)
}
ComplianceStatus::NotScanned => write!(f, "? Not Scanned"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_manifest_creation() {
let phase4_config = Phase4Config::default();
let feature_flags = CalibV22Config {
enabled: true,
rollout_percentage: 100,
rollout_stage: "production".to_string(),
bucket_strategy: crate::calibration::feature_flags::BucketStrategy {
method: crate::calibration::feature_flags::BucketMethod::RepositoryHash {
salt: "test".to_string()
},
bucket_salt: "test".to_string(),
sticky_sessions: true,
override_buckets: HashMap::new(),
},
sla_gates: crate::calibration::feature_flags::SlaGateConfig {
max_p99_latency_increase_us: 1000.0,
max_aece_tau_threshold: 0.02,
max_confidence_shift: 0.1,
require_zero_sla_recall_change: true,
evaluation_window_minutes: 15,
consecutive_breach_threshold: 3,
},
auto_revert_config: crate::calibration::feature_flags::AutoRevertConfig {
enabled: true,
breach_window_threshold: 2,
breach_window_duration_minutes: 30,
revert_cooldown_minutes: 60,
max_reverts_per_day: 3,
},
config_fingerprint: "test".to_string(),
rollout_start_time: Utc::now(),
promotion_criteria: crate::calibration::feature_flags::PromotionCriteria {
min_observation_hours: 24,
required_health_status: crate::calibration::drift_monitor::HealthStatus::Green,
max_aece_degradation: 0.005,
require_p99_compliance: true,
min_success_rate: 0.99,
},
};
let manifest = CalibrationManifest::new(
"test".to_string(),
"test-deployment-1".to_string(),
phase4_config,
feature_flags,
).unwrap();
assert_eq!(manifest.environment, "test");
assert_eq!(manifest.deployment_id, "test-deployment-1");
assert_eq!(manifest.manifest_version, "1.0.0");
assert!(manifest.config_fingerprint.config_hash.len() == 64);
}
#[test]
fn test_configuration_fingerprint_generation() {
let phase4_config = Phase4Config::default();
let feature_flags = CalibV22Config {
enabled: true,
rollout_percentage: 50,
rollout_stage: "staging".to_string(),
bucket_strategy: crate::calibration::feature_flags::BucketStrategy {
method: crate::calibration::feature_flags::BucketMethod::Random,
bucket_salt: "test".to_string(),
sticky_sessions: false,
override_buckets: HashMap::new(),
},
sla_gates: crate::calibration::feature_flags::SlaGateConfig {
max_p99_latency_increase_us: 500.0,
max_aece_tau_threshold: 0.015,
max_confidence_shift: 0.05,
require_zero_sla_recall_change: false,
evaluation_window_minutes: 10,
consecutive_breach_threshold: 2,
},
auto_revert_config: crate::calibration::feature_flags::AutoRevertConfig {
enabled: false,
breach_window_threshold: 1,
breach_window_duration_minutes: 15,
revert_cooldown_minutes: 30,
max_reverts_per_day: 1,
},
config_fingerprint: "staging".to_string(),
rollout_start_time: Utc::now(),
promotion_criteria: crate::calibration::feature_flags::PromotionCriteria {
min_observation_hours: 12,
required_health_status: crate::calibration::drift_monitor::HealthStatus::Green,
max_aece_degradation: 0.01,
require_p99_compliance: false,
min_success_rate: 0.95,
},
};
let float_rounding = FloatRoundingConfig::default();
let quantile_policy = QuantilePolicyConfig::default();
let bootstrap_config = BootstrapConfig::default();
let fingerprint = CalibrationManifest::generate_configuration_fingerprint(
&phase4_config,
&feature_flags,
&float_rounding,
&quantile_policy,
&bootstrap_config,
).unwrap();
assert_eq!(fingerprint.config_hash.len(), 64);
assert_eq!(fingerprint.algorithm, "SHA-256");
assert!(fingerprint.rust_lib_hash.len() == 64);
}
#[test]
fn test_sha256_hash() {
let hash1 = CalibrationManifest::sha256_hash("test data");
let hash2 = CalibrationManifest::sha256_hash("test data");
let hash3 = CalibrationManifest::sha256_hash("different data");
assert_eq!(hash1, hash2);
assert_ne!(hash1, hash3);
assert_eq!(hash1.len(), 64);
}
#[test]
fn test_sbom_entry_creation() {
let entry = SbomEntry {
name: "serde".to_string(),
version: "1.0.0".to_string(),
license: Some("MIT".to_string()),
source_url: Some("https://github.com/serde-rs/serde".to_string()),
hash: CalibrationManifest::sha256_hash("serde-1.0.0"),
component_type: SbomComponentType::RustLibrary,
security_scan: None,
};
assert_eq!(entry.name, "serde");
assert_eq!(entry.hash.len(), 64);
assert!(matches!(entry.component_type, SbomComponentType::RustLibrary));
}
#[test]
fn test_json_serialization() {
let phase4_config = Phase4Config::default();
let feature_flags = CalibV22Config {
enabled: true,
rollout_percentage: 100,
rollout_stage: "test".to_string(),
bucket_strategy: crate::calibration::feature_flags::BucketStrategy {
method: crate::calibration::feature_flags::BucketMethod::RepositoryHash {
salt: "test".to_string()
},
bucket_salt: "test".to_string(),
sticky_sessions: true,
override_buckets: HashMap::new(),
},
sla_gates: crate::calibration::feature_flags::SlaGateConfig {
max_p99_latency_increase_us: 1000.0,
max_aece_tau_threshold: 0.02,
max_confidence_shift: 0.1,
require_zero_sla_recall_change: true,
evaluation_window_minutes: 15,
consecutive_breach_threshold: 3,
},
auto_revert_config: crate::calibration::feature_flags::AutoRevertConfig {
enabled: true,
breach_window_threshold: 2,
breach_window_duration_minutes: 30,
revert_cooldown_minutes: 60,
max_reverts_per_day: 3,
},
config_fingerprint: "test".to_string(),
rollout_start_time: Utc::now(),
promotion_criteria: crate::calibration::feature_flags::PromotionCriteria {
min_observation_hours: 24,
required_health_status: crate::calibration::drift_monitor::HealthStatus::Green,
max_aece_degradation: 0.005,
require_p99_compliance: true,
min_success_rate: 0.99,
},
};
let manifest = CalibrationManifest::new(
"test".to_string(),
"test-deployment-1".to_string(),
phase4_config,
feature_flags,
).unwrap();
let json = manifest.to_json().unwrap();
let deserialized = CalibrationManifest::from_json(&json).unwrap();
assert_eq!(manifest.deployment_id, deserialized.deployment_id);
assert_eq!(manifest.config_fingerprint.config_hash, deserialized.config_fingerprint.config_hash);
}
}