swarm-engine-core 0.1.6

Core types and orchestration for SwarmEngine
Documentation
//! ValidationResult - 検証結果

use serde::{Deserialize, Serialize};

/// 検証結果
///
/// Validator による検証の出力。Profile に保存される。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationResult {
    /// 合格したか
    pub passed: bool,
    /// ベースライン成績 (0.0-1.0)
    pub baseline: f64,
    /// 検証時成績 (0.0-1.0)
    pub current: f64,
    /// 使用した戦略名
    pub strategy: String,
    /// 失敗理由(失敗時のみ)
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub failure_reason: Option<String>,
    /// 検証に使用したサンプル数
    pub sample_count: usize,
}

impl ValidationResult {
    /// 成功結果を作成
    pub fn pass(baseline: f64, current: f64, strategy: &str, sample_count: usize) -> Self {
        Self {
            passed: true,
            baseline,
            current,
            strategy: strategy.to_string(),
            failure_reason: None,
            sample_count,
        }
    }

    /// 失敗結果を作成
    pub fn fail(
        baseline: f64,
        current: f64,
        strategy: &str,
        reason: impl Into<String>,
        sample_count: usize,
    ) -> Self {
        Self {
            passed: false,
            baseline,
            current,
            strategy: strategy.to_string(),
            failure_reason: Some(reason.into()),
            sample_count,
        }
    }

    /// 改善率を計算 (%)
    pub fn improvement(&self) -> f64 {
        if self.baseline > 0.0 {
            (self.current / self.baseline - 1.0) * 100.0
        } else {
            0.0
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_pass_result() {
        let result = ValidationResult::pass(0.7, 0.85, "no_regression", 100);
        assert!(result.passed);
        assert!(result.failure_reason.is_none());
        assert!((result.improvement() - 21.43).abs() < 0.1);
    }

    #[test]
    fn test_fail_result() {
        let result = ValidationResult::fail(0.7, 0.65, "no_regression", "regression detected", 100);
        assert!(!result.passed);
        assert!(result.failure_reason.is_some());
    }

    #[test]
    fn test_serialization() {
        let result = ValidationResult::pass(0.7, 0.8, "improvement", 50);
        let json = serde_json::to_string(&result).unwrap();
        let restored: ValidationResult = serde_json::from_str(&json).unwrap();
        assert_eq!(restored.passed, result.passed);
        assert_eq!(restored.strategy, result.strategy);
    }
}