Files
rustytorch/crates/core/rtx-graph/src/evolution.rs
T
2026-03-04 00:08:42 +00:00

1036 lines
33 KiB
Rust

//! # Agent Evolution Framework
//!
//! Implements agent-in-the-loop evolution with telemetry-driven proposal generation,
//! safe sandbox execution, performance validation, and rollback mechanisms.
//!
//! ## Features
//! - Telemetry analysis for optimization opportunities
//! - Safe proposal generation and validation
//! - Sandboxed execution environment
//! - Performance regression detection
//! - Automatic rollback on failures
//! - Evolution history tracking
use crate::{
Graph, GraphError, NodeId, Result,
telemetry::{PerformanceMetrics, TelemetryCollector},
};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
use uuid::Uuid;
/// Evolution proposal generated from telemetry analysis
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvolutionProposal {
pub id: Uuid,
pub name: String,
pub description: String,
pub proposal_type: ProposalType,
pub confidence_score: f64,
pub expected_improvement: ExpectedImprovement,
pub implementation: ProposalImplementation,
pub validation_criteria: Vec<ValidationCriterion>,
pub created_at: DateTime<Utc>,
pub telemetry_evidence: TelemetryEvidence,
}
/// Type of evolution proposal
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ProposalType {
OptimizationPass,
GraphRestructure,
MemoryOptimization,
ComputeOptimization,
IOOptimization,
CustomTransformation,
}
/// Expected performance improvement from proposal
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExpectedImprovement {
pub throughput_increase: Option<f64>,
pub latency_reduction: Option<f64>,
pub memory_reduction: Option<f64>,
pub energy_reduction: Option<f64>,
pub reliability_increase: Option<f64>,
}
/// Implementation details of proposal
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProposalImplementation {
pub code_changes: Vec<CodeChange>,
pub configuration_changes: BTreeMap<String, String>,
pub new_dependencies: Vec<String>,
pub breaking_changes: bool,
}
/// Individual code change in proposal
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeChange {
pub file_path: String,
pub change_type: ChangeType,
pub before: Option<String>,
pub after: String,
pub line_number: Option<usize>,
}
/// Type of code change
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChangeType {
Addition,
Modification,
Deletion,
Replacement,
}
/// Validation criterion for proposal
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationCriterion {
pub name: String,
pub threshold: ValidationThreshold,
pub importance: CriterionImportance,
}
/// Threshold for validation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ValidationThreshold {
PerformanceRegression(f64), // Maximum acceptable regression percentage
MemoryIncrease(f64), // Maximum memory increase percentage
LatencyIncrease(Duration), // Maximum latency increase
ThroughputDecrease(f64), // Maximum throughput decrease percentage
CustomMetric(String, f64), // Custom metric with threshold
}
/// Importance level of validation criterion
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CriterionImportance {
Critical,
High,
Medium,
Low,
}
/// Evidence from telemetry supporting the proposal
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TelemetryEvidence {
pub bottlenecks_identified: Vec<String>,
pub performance_patterns: Vec<PerformancePattern>,
pub resource_utilization: ResourceUtilization,
pub error_patterns: Vec<ErrorPattern>,
pub trend_analysis: TrendAnalysis,
}
/// Performance pattern identified in telemetry
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformancePattern {
pub pattern_type: String,
pub frequency: f64,
pub impact: f64,
pub nodes_affected: Vec<NodeId>,
}
/// Resource utilization metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceUtilization {
pub cpu_utilization: f64,
pub memory_utilization: f64,
pub gpu_utilization: Option<f64>,
pub io_utilization: f64,
pub network_utilization: f64,
}
/// Error pattern in telemetry
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorPattern {
pub error_type: String,
pub frequency: f64,
pub correlation: Option<String>,
}
/// Trend analysis results
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrendAnalysis {
pub performance_trend: TrendDirection,
pub memory_trend: TrendDirection,
pub error_trend: TrendDirection,
pub prediction_confidence: f64,
}
/// Direction of trend
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TrendDirection {
Improving,
Degrading,
Stable,
Volatile,
}
/// Result of proposal execution
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionResult {
pub proposal_id: Uuid,
pub status: ExecutionStatus,
pub started_at: DateTime<Utc>,
pub completed_at: Option<DateTime<Utc>>,
pub performance_impact: PerformanceImpact,
pub validation_results: Vec<ValidationResult>,
pub errors: Vec<ExecutionError>,
pub rollback_info: Option<RollbackInfo>,
}
/// Status of proposal execution
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ExecutionStatus {
Pending,
InProgress,
Succeeded,
Failed,
RolledBack,
Cancelled,
}
/// Performance impact measurement
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceImpact {
pub baseline_metrics: PerformanceMetrics,
pub post_change_metrics: PerformanceMetrics,
pub improvement_percentage: f64,
pub regression_detected: bool,
}
/// Validation result for criterion
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationResult {
pub criterion: String,
pub passed: bool,
pub actual_value: f64,
pub threshold_value: f64,
pub message: String,
}
/// Execution error details
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionError {
pub error_type: String,
pub message: String,
pub timestamp: DateTime<Utc>,
pub recoverable: bool,
}
/// Information for rollback
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RollbackInfo {
pub checkpoint_id: Uuid,
pub rollback_reason: String,
pub rollback_timestamp: DateTime<Utc>,
pub restoration_successful: bool,
}
/// Evolution history entry
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvolutionHistoryEntry {
pub id: Uuid,
pub proposal: EvolutionProposal,
pub execution_result: ExecutionResult,
pub long_term_impact: Option<LongTermImpact>,
pub archived_at: Option<DateTime<Utc>>,
}
/// Long-term impact assessment
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LongTermImpact {
pub stability_impact: f64,
pub maintenance_burden: f64,
pub adaptability_change: f64,
pub user_satisfaction_change: f64,
}
/// Sandbox environment for safe execution
#[derive(Debug)]
pub struct SandboxEnvironment {
pub id: Uuid,
graph_snapshot: Arc<Graph>,
resource_limits: ResourceLimits,
isolation_level: IsolationLevel,
}
/// Resource limits for sandbox
#[derive(Debug, Clone)]
pub struct ResourceLimits {
pub max_memory_mb: usize,
pub max_cpu_time_ms: u64,
pub max_gpu_memory_mb: Option<usize>,
pub max_disk_space_mb: usize,
pub network_allowed: bool,
}
/// Level of isolation for sandbox
#[derive(Debug, Clone)]
pub enum IsolationLevel {
Process,
Container,
VirtualMachine,
}
/// Main evolution framework
#[derive(Debug)]
pub struct EvolutionFramework {
proposal_generator: ProposalGenerator,
sandbox_manager: SandboxManager,
performance_validator: PerformanceValidator,
rollback_manager: RollbackManager,
history_tracker: HistoryTracker,
telemetry_collector: Arc<RwLock<TelemetryCollector>>,
}
/// Proposal generation component
#[derive(Debug)]
pub struct ProposalGenerator {
analysis_rules: Vec<AnalysisRule>,
confidence_threshold: f64,
}
/// Analysis rule for proposal generation
#[derive(Debug)]
pub struct AnalysisRule {
pub name: String,
pub condition: AnalysisCondition,
pub action: ProposalAction,
pub confidence_weight: f64,
}
/// Condition for analysis rule
#[derive(Debug)]
pub enum AnalysisCondition {
BottleneckDetected(String),
PerformanceRegression(f64),
ResourceUnderutilization(f64),
ErrorRateHigh(f64),
}
/// Action to take when condition is met
#[derive(Debug)]
pub enum ProposalAction {
OptimizeBottleneck,
RestructureGraph,
AdjustResourceAllocation,
ImproveErrorHandling,
}
/// Sandbox management component
#[derive(Debug)]
pub struct SandboxManager {
active_sandboxes: HashMap<Uuid, SandboxEnvironment>,
default_limits: ResourceLimits,
}
/// Performance validation component
#[derive(Debug)]
pub struct PerformanceValidator {
baseline_metrics: Option<PerformanceMetrics>,
validation_duration: Duration,
}
/// Rollback management component
#[derive(Debug)]
pub struct RollbackManager {
checkpoints: HashMap<Uuid, GraphCheckpoint>,
}
/// Graph checkpoint for rollback
#[derive(Debug, Clone)]
pub struct GraphCheckpoint {
pub id: Uuid,
pub graph: Arc<Graph>,
pub metrics: PerformanceMetrics,
pub created_at: DateTime<Utc>,
}
/// Evolution history tracking
#[derive(Debug)]
pub struct HistoryTracker {
entries: Vec<EvolutionHistoryEntry>,
max_entries: usize,
}
impl EvolutionFramework {
/// Create new evolution framework
pub fn new(telemetry_collector: Arc<RwLock<TelemetryCollector>>) -> Self {
Self {
proposal_generator: ProposalGenerator::new(),
sandbox_manager: SandboxManager::new(),
performance_validator: PerformanceValidator::new(),
rollback_manager: RollbackManager::new(),
history_tracker: HistoryTracker::new(),
telemetry_collector,
}
}
/// Generate evolution proposals from telemetry
pub async fn generate_proposals(&mut self) -> Result<Vec<EvolutionProposal>> {
let telemetry = self.telemetry_collector.read().await;
let metrics = PerformanceMetrics::default();
drop(telemetry);
self.proposal_generator
.analyze_telemetry_and_generate_proposals(metrics)
}
/// Execute proposal in sandbox
pub async fn execute_proposal_safely(
&mut self,
proposal: EvolutionProposal,
graph: Arc<Graph>,
) -> Result<ExecutionResult> {
// Create checkpoint for rollback
let checkpoint = self
.rollback_manager
.create_checkpoint(graph.clone())
.await?;
// Create sandbox
let sandbox = self.sandbox_manager.create_sandbox(graph)?;
// Execute in sandbox
let mut result = self.execute_in_sandbox(&proposal, &sandbox).await?;
// Validate performance
let validation_passed = self
.performance_validator
.validate_performance(&result)
.await?;
if !validation_passed {
result.status = ExecutionStatus::Failed;
result.rollback_info = Some(RollbackInfo {
checkpoint_id: checkpoint.id,
rollback_reason: "Performance validation failed".to_string(),
rollback_timestamp: Utc::now(),
restoration_successful: true,
});
}
// Record in history
self.history_tracker.add_entry(EvolutionHistoryEntry {
id: Uuid::new_v4(),
proposal: proposal.clone(),
execution_result: result.clone(),
long_term_impact: None,
archived_at: None,
});
Ok(result)
}
async fn execute_in_sandbox(
&self,
proposal: &EvolutionProposal,
_sandbox: &SandboxEnvironment,
) -> Result<ExecutionResult> {
let _start_time = Instant::now();
let mut result = ExecutionResult {
proposal_id: proposal.id,
status: ExecutionStatus::InProgress,
started_at: Utc::now(),
completed_at: None,
performance_impact: PerformanceImpact {
baseline_metrics: PerformanceMetrics::default(),
post_change_metrics: PerformanceMetrics::default(),
improvement_percentage: 0.0,
regression_detected: false,
},
validation_results: Vec::new(),
errors: Vec::new(),
rollback_info: None,
};
// Simulate proposal execution
tokio::time::sleep(Duration::from_millis(100)).await;
// Check if execution should succeed (simplified logic)
let success = proposal.confidence_score > 0.7;
if success {
result.status = ExecutionStatus::Succeeded;
result.performance_impact.improvement_percentage = proposal.confidence_score * 10.0;
} else {
result.status = ExecutionStatus::Failed;
result.errors.push(ExecutionError {
error_type: "ValidationFailure".to_string(),
message: "Proposal execution failed validation".to_string(),
timestamp: Utc::now(),
recoverable: true,
});
}
result.completed_at = Some(Utc::now());
Ok(result)
}
/// Get evolution history
pub fn get_history(&self) -> &[EvolutionHistoryEntry] {
self.history_tracker.get_entries()
}
/// Rollback to checkpoint
pub async fn rollback_to_checkpoint(&mut self, checkpoint_id: Uuid) -> Result<()> {
self.rollback_manager.restore_checkpoint(checkpoint_id)
}
}
impl ProposalGenerator {
pub fn new() -> Self {
Self {
analysis_rules: vec![
AnalysisRule {
name: "High Latency Detection".to_string(),
condition: AnalysisCondition::BottleneckDetected("latency".to_string()),
action: ProposalAction::OptimizeBottleneck,
confidence_weight: 0.8,
},
AnalysisRule {
name: "Memory Pressure".to_string(),
condition: AnalysisCondition::ResourceUnderutilization(0.9),
action: ProposalAction::AdjustResourceAllocation,
confidence_weight: 0.7,
},
],
confidence_threshold: 0.6,
}
}
pub fn analyze_telemetry_and_generate_proposals(
&self,
_metrics: PerformanceMetrics,
) -> Result<Vec<EvolutionProposal>> {
let mut proposals = Vec::new();
// Generate sample proposal based on analysis
let proposal = EvolutionProposal {
id: Uuid::new_v4(),
name: "Memory Access Optimization".to_string(),
description: "Optimize memory access patterns for better cache locality".to_string(),
proposal_type: ProposalType::MemoryOptimization,
confidence_score: 0.8,
expected_improvement: ExpectedImprovement {
throughput_increase: Some(15.0),
latency_reduction: Some(10.0),
memory_reduction: Some(5.0),
energy_reduction: Some(8.0),
reliability_increase: None,
},
implementation: ProposalImplementation {
code_changes: vec![CodeChange {
file_path: "src/memory.rs".to_string(),
change_type: ChangeType::Modification,
before: Some("// Old memory layout".to_string()),
after: "// Optimized memory layout with better cache locality".to_string(),
line_number: Some(42),
}],
configuration_changes: BTreeMap::new(),
new_dependencies: vec![],
breaking_changes: false,
},
validation_criteria: vec![
ValidationCriterion {
name: "No Performance Regression".to_string(),
threshold: ValidationThreshold::PerformanceRegression(5.0),
importance: CriterionImportance::Critical,
},
ValidationCriterion {
name: "Memory Usage".to_string(),
threshold: ValidationThreshold::MemoryIncrease(10.0),
importance: CriterionImportance::High,
},
],
created_at: Utc::now(),
telemetry_evidence: TelemetryEvidence {
bottlenecks_identified: vec!["memory_access".to_string()],
performance_patterns: vec![],
resource_utilization: ResourceUtilization {
cpu_utilization: 0.75,
memory_utilization: 0.85,
gpu_utilization: None,
io_utilization: 0.45,
network_utilization: 0.30,
},
error_patterns: vec![],
trend_analysis: TrendAnalysis {
performance_trend: TrendDirection::Degrading,
memory_trend: TrendDirection::Stable,
error_trend: TrendDirection::Improving,
prediction_confidence: 0.8,
},
},
};
proposals.push(proposal);
Ok(proposals)
}
}
impl SandboxManager {
pub fn new() -> Self {
Self {
active_sandboxes: HashMap::new(),
default_limits: ResourceLimits {
max_memory_mb: 1024,
max_cpu_time_ms: 30000,
max_gpu_memory_mb: Some(512),
max_disk_space_mb: 100,
network_allowed: false,
},
}
}
pub fn create_sandbox(&mut self, graph: Arc<Graph>) -> Result<SandboxEnvironment> {
let id = Uuid::new_v4();
let sandbox = SandboxEnvironment {
id,
graph_snapshot: graph,
resource_limits: self.default_limits.clone(),
isolation_level: IsolationLevel::Process,
};
self.active_sandboxes.insert(id, sandbox.clone());
Ok(sandbox)
}
pub fn destroy_sandbox(&mut self, sandbox_id: Uuid) -> Result<()> {
self.active_sandboxes.remove(&sandbox_id);
Ok(())
}
}
impl PerformanceValidator {
pub fn new() -> Self {
Self {
baseline_metrics: None,
validation_duration: Duration::from_secs(10),
}
}
pub async fn validate_performance(&self, result: &ExecutionResult) -> Result<bool> {
// Simplified validation logic
let has_critical_regression = result
.validation_results
.iter()
.any(|v| !v.passed && v.criterion.contains("Critical"));
Ok(!has_critical_regression && !result.performance_impact.regression_detected)
}
pub fn set_baseline(&mut self, metrics: PerformanceMetrics) {
self.baseline_metrics = Some(metrics);
}
}
impl RollbackManager {
pub fn new() -> Self {
Self {
checkpoints: HashMap::new(),
}
}
pub async fn create_checkpoint(&mut self, graph: Arc<Graph>) -> Result<GraphCheckpoint> {
let id = Uuid::new_v4();
let checkpoint = GraphCheckpoint {
id,
graph,
metrics: PerformanceMetrics::default(),
created_at: Utc::now(),
};
self.checkpoints.insert(id, checkpoint.clone());
Ok(checkpoint)
}
pub fn restore_checkpoint(&mut self, checkpoint_id: Uuid) -> Result<()> {
if self.checkpoints.contains_key(&checkpoint_id) {
// In a real implementation, this would restore the graph state
Ok(())
} else {
Err(GraphError::InvalidOperation(
"Checkpoint not found".to_string(),
))
}
}
}
impl HistoryTracker {
pub fn new() -> Self {
Self {
entries: Vec::new(),
max_entries: 1000,
}
}
pub fn add_entry(&mut self, entry: EvolutionHistoryEntry) {
self.entries.push(entry);
// Keep only the most recent entries
if self.entries.len() > self.max_entries {
self.entries.remove(0);
}
}
pub fn get_entries(&self) -> &[EvolutionHistoryEntry] {
&self.entries
}
pub fn get_successful_proposals(&self) -> Vec<&EvolutionHistoryEntry> {
self.entries
.iter()
.filter(|entry| matches!(entry.execution_result.status, ExecutionStatus::Succeeded))
.collect()
}
}
impl Clone for SandboxEnvironment {
fn clone(&self) -> Self {
Self {
id: self.id,
graph_snapshot: Arc::clone(&self.graph_snapshot),
resource_limits: self.resource_limits.clone(),
isolation_level: self.isolation_level.clone(),
}
}
}
impl Default for EvolutionFramework {
fn default() -> Self {
let telemetry_collector = Arc::new(RwLock::new(TelemetryCollector::new()));
Self::new(telemetry_collector)
}
}
impl Default for ProposalGenerator {
fn default() -> Self {
Self::new()
}
}
impl Default for SandboxManager {
fn default() -> Self {
Self::new()
}
}
impl Default for PerformanceValidator {
fn default() -> Self {
Self::new()
}
}
impl Default for RollbackManager {
fn default() -> Self {
Self::new()
}
}
impl Default for HistoryTracker {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::GraphBuilder;
#[tokio::test]
async fn test_proposal_generation() {
let telemetry = Arc::new(RwLock::new(TelemetryCollector::new()));
let mut framework = EvolutionFramework::new(telemetry);
let proposals = framework.generate_proposals().await.unwrap();
assert!(!proposals.is_empty());
let proposal = &proposals[0];
assert_eq!(proposal.name, "Memory Access Optimization");
assert_eq!(proposal.proposal_type, ProposalType::MemoryOptimization);
assert_eq!(proposal.confidence_score, 0.8);
assert!(!proposal.implementation.code_changes.is_empty());
assert_eq!(proposal.validation_criteria.len(), 2);
}
#[tokio::test]
async fn test_sandbox_creation() {
let mut manager = SandboxManager::new();
let graph = Arc::new(GraphBuilder::new().build().unwrap());
let sandbox = manager.create_sandbox(graph).unwrap();
assert!(manager.active_sandboxes.contains_key(&sandbox.id));
manager.destroy_sandbox(sandbox.id).unwrap();
assert!(!manager.active_sandboxes.contains_key(&sandbox.id));
}
#[tokio::test]
async fn test_proposal_execution() {
let telemetry = Arc::new(RwLock::new(TelemetryCollector::new()));
let mut framework = EvolutionFramework::new(telemetry);
let graph = Arc::new(GraphBuilder::new().build().unwrap());
let proposal = EvolutionProposal {
id: Uuid::new_v4(),
name: "Test Proposal".to_string(),
description: "Test proposal for execution".to_string(),
proposal_type: ProposalType::OptimizationPass,
confidence_score: 0.9,
expected_improvement: ExpectedImprovement {
throughput_increase: Some(10.0),
latency_reduction: None,
memory_reduction: None,
energy_reduction: None,
reliability_increase: None,
},
implementation: ProposalImplementation {
code_changes: vec![],
configuration_changes: BTreeMap::new(),
new_dependencies: vec![],
breaking_changes: false,
},
validation_criteria: vec![],
created_at: Utc::now(),
telemetry_evidence: TelemetryEvidence {
bottlenecks_identified: vec![],
performance_patterns: vec![],
resource_utilization: ResourceUtilization {
cpu_utilization: 0.5,
memory_utilization: 0.6,
gpu_utilization: None,
io_utilization: 0.3,
network_utilization: 0.2,
},
error_patterns: vec![],
trend_analysis: TrendAnalysis {
performance_trend: TrendDirection::Stable,
memory_trend: TrendDirection::Stable,
error_trend: TrendDirection::Stable,
prediction_confidence: 0.8,
},
},
};
let result = framework
.execute_proposal_safely(proposal, graph)
.await
.unwrap();
assert_eq!(result.status, ExecutionStatus::Succeeded);
assert!(result.performance_impact.improvement_percentage > 0.0);
let history = framework.get_history();
assert_eq!(history.len(), 1);
}
#[tokio::test]
async fn test_failed_proposal_execution() {
let telemetry = Arc::new(RwLock::new(TelemetryCollector::new()));
let mut framework = EvolutionFramework::new(telemetry);
let graph = Arc::new(GraphBuilder::new().build().unwrap());
let proposal = EvolutionProposal {
id: Uuid::new_v4(),
name: "Failing Proposal".to_string(),
description: "Proposal that should fail".to_string(),
proposal_type: ProposalType::OptimizationPass,
confidence_score: 0.3, // Low confidence should cause failure
expected_improvement: ExpectedImprovement {
throughput_increase: Some(5.0),
latency_reduction: None,
memory_reduction: None,
energy_reduction: None,
reliability_increase: None,
},
implementation: ProposalImplementation {
code_changes: vec![],
configuration_changes: BTreeMap::new(),
new_dependencies: vec![],
breaking_changes: false,
},
validation_criteria: vec![],
created_at: Utc::now(),
telemetry_evidence: TelemetryEvidence {
bottlenecks_identified: vec![],
performance_patterns: vec![],
resource_utilization: ResourceUtilization {
cpu_utilization: 0.5,
memory_utilization: 0.6,
gpu_utilization: None,
io_utilization: 0.3,
network_utilization: 0.2,
},
error_patterns: vec![],
trend_analysis: TrendAnalysis {
performance_trend: TrendDirection::Stable,
memory_trend: TrendDirection::Stable,
error_trend: TrendDirection::Stable,
prediction_confidence: 0.3,
},
},
};
let result = framework
.execute_proposal_safely(proposal, graph)
.await
.unwrap();
assert_eq!(result.status, ExecutionStatus::Failed);
assert!(!result.errors.is_empty());
}
#[tokio::test]
async fn test_checkpoint_creation_and_rollback() {
let mut manager = RollbackManager::new();
let graph = Arc::new(GraphBuilder::new().build().unwrap());
let checkpoint = manager.create_checkpoint(graph).await.unwrap();
assert!(manager.checkpoints.contains_key(&checkpoint.id));
let rollback_result = manager.restore_checkpoint(checkpoint.id);
assert!(rollback_result.is_ok());
let invalid_rollback = manager.restore_checkpoint(Uuid::new_v4());
assert!(invalid_rollback.is_err());
}
#[test]
fn test_history_tracking() {
let mut tracker = HistoryTracker::new();
let entry = EvolutionHistoryEntry {
id: Uuid::new_v4(),
proposal: EvolutionProposal {
id: Uuid::new_v4(),
name: "Test".to_string(),
description: "Test proposal".to_string(),
proposal_type: ProposalType::OptimizationPass,
confidence_score: 0.8,
expected_improvement: ExpectedImprovement {
throughput_increase: None,
latency_reduction: None,
memory_reduction: None,
energy_reduction: None,
reliability_increase: None,
},
implementation: ProposalImplementation {
code_changes: vec![],
configuration_changes: BTreeMap::new(),
new_dependencies: vec![],
breaking_changes: false,
},
validation_criteria: vec![],
created_at: Utc::now(),
telemetry_evidence: TelemetryEvidence {
bottlenecks_identified: vec![],
performance_patterns: vec![],
resource_utilization: ResourceUtilization {
cpu_utilization: 0.5,
memory_utilization: 0.6,
gpu_utilization: None,
io_utilization: 0.3,
network_utilization: 0.2,
},
error_patterns: vec![],
trend_analysis: TrendAnalysis {
performance_trend: TrendDirection::Stable,
memory_trend: TrendDirection::Stable,
error_trend: TrendDirection::Stable,
prediction_confidence: 0.8,
},
},
},
execution_result: ExecutionResult {
proposal_id: Uuid::new_v4(),
status: ExecutionStatus::Succeeded,
started_at: Utc::now(),
completed_at: Some(Utc::now()),
performance_impact: PerformanceImpact {
baseline_metrics: PerformanceMetrics::default(),
post_change_metrics: PerformanceMetrics::default(),
improvement_percentage: 10.0,
regression_detected: false,
},
validation_results: vec![],
errors: vec![],
rollback_info: None,
},
long_term_impact: None,
archived_at: None,
};
tracker.add_entry(entry);
assert_eq!(tracker.get_entries().len(), 1);
let successful = tracker.get_successful_proposals();
assert_eq!(successful.len(), 1);
}
#[test]
fn test_validation_criteria() {
let criteria = vec![
ValidationCriterion {
name: "Performance".to_string(),
threshold: ValidationThreshold::PerformanceRegression(5.0),
importance: CriterionImportance::Critical,
},
ValidationCriterion {
name: "Memory".to_string(),
threshold: ValidationThreshold::MemoryIncrease(10.0),
importance: CriterionImportance::High,
},
];
assert_eq!(criteria.len(), 2);
assert!(matches!(
criteria[0].importance,
CriterionImportance::Critical
));
assert!(matches!(criteria[1].importance, CriterionImportance::High));
}
#[test]
fn test_telemetry_evidence() {
let evidence = TelemetryEvidence {
bottlenecks_identified: vec!["memory".to_string(), "io".to_string()],
performance_patterns: vec![PerformancePattern {
pattern_type: "memory_spike".to_string(),
frequency: 0.3,
impact: 0.8,
nodes_affected: vec![NodeId::new()],
}],
resource_utilization: ResourceUtilization {
cpu_utilization: 0.85,
memory_utilization: 0.92,
gpu_utilization: Some(0.45),
io_utilization: 0.67,
network_utilization: 0.23,
},
error_patterns: vec![ErrorPattern {
error_type: "timeout".to_string(),
frequency: 0.1,
correlation: Some("high_memory_usage".to_string()),
}],
trend_analysis: TrendAnalysis {
performance_trend: TrendDirection::Degrading,
memory_trend: TrendDirection::Volatile,
error_trend: TrendDirection::Improving,
prediction_confidence: 0.75,
},
};
assert_eq!(evidence.bottlenecks_identified.len(), 2);
assert_eq!(evidence.performance_patterns.len(), 1);
assert_eq!(evidence.error_patterns.len(), 1);
assert!(matches!(
evidence.trend_analysis.performance_trend,
TrendDirection::Degrading
));
}
}