reputation-core 0.1.0

Core calculation engine for the KnowThat Reputation System with advanced scoring algorithms
Documentation
//! Empirical score calculation module
//! 
//! This module handles the calculation of empirical reputation scores based on
//! reviews and ratings.

use reputation_types::AgentData;

/// Calculates the empirical reputation score based on reviews and ratings
/// 
/// The empirical score is derived from:
/// - Average rating (1-5 scale) converted to 0-100 scale
/// - Returns 50.0 (neutral) when no reviews are available
/// 
/// # Formula
/// 
/// `empirical_score = (average_rating - 1.0) * 25.0`
/// 
/// This converts:
/// - 1.0 rating → 0 score
/// - 3.0 rating → 50 score
/// - 5.0 rating → 100 score
#[inline(always)]
pub(crate) fn calculate_empirical(agent: &AgentData) -> f64 {
    if agent.total_reviews == 0 {
        return 50.0; // Neutral score when no data
    }

    if let Some(avg) = agent.average_rating {
        // Rating should be between 1.0 and 5.0, already validated
        (avg - 1.0) * 25.0
    } else {
        50.0 // Neutral score when no rating available
    }
}

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

    fn create_test_agent() -> AgentData {
        AgentData {
            did: "did:test:123".to_string(),
            created_at: Utc::now(),
            mcp_level: None,
            identity_verified: false,
            security_audit_passed: false,
            open_source: false,
            total_interactions: 0,
            total_reviews: 0,
            average_rating: None,
            positive_reviews: 0,
            negative_reviews: 0,
        }
    }

    #[test]
    fn test_no_reviews() {
        let agent = create_test_agent();
        assert_eq!(calculate_empirical(&agent), 50.0);
    }

    #[test]
    fn test_rating_conversion() {
        let mut agent = create_test_agent();
        agent.total_reviews = 10;
        
        // Test minimum rating
        agent.average_rating = Some(1.0);
        assert_eq!(calculate_empirical(&agent), 0.0);
        
        // Test neutral rating
        agent.average_rating = Some(3.0);
        assert_eq!(calculate_empirical(&agent), 50.0);
        
        // Test maximum rating
        agent.average_rating = Some(5.0);
        assert_eq!(calculate_empirical(&agent), 100.0);
        
        // Test intermediate ratings
        agent.average_rating = Some(2.0);
        assert_eq!(calculate_empirical(&agent), 25.0);
        
        agent.average_rating = Some(4.0);
        assert_eq!(calculate_empirical(&agent), 75.0);
        
        agent.average_rating = Some(4.5);
        assert_eq!(calculate_empirical(&agent), 87.5);
    }

    #[test]
    fn test_reviews_but_no_rating() {
        let mut agent = create_test_agent();
        agent.total_reviews = 10;
        agent.average_rating = None;
        
        // Should return neutral score even with reviews
        assert_eq!(calculate_empirical(&agent), 50.0);
    }

    #[test]
    fn test_fractional_ratings() {
        let mut agent = create_test_agent();
        agent.total_reviews = 10;
        
        // Test various fractional ratings
        agent.average_rating = Some(1.5);
        assert!((calculate_empirical(&agent) - 12.5).abs() < 0.0001);
        
        agent.average_rating = Some(2.7);
        assert!((calculate_empirical(&agent) - 42.5).abs() < 0.0001);
        
        agent.average_rating = Some(3.3);
        assert!((calculate_empirical(&agent) - 57.5).abs() < 0.0001);
        
        agent.average_rating = Some(4.2);
        assert!((calculate_empirical(&agent) - 80.0).abs() < 0.0001);
    }
}