reputation_core/
config.rs

1use serde::{Deserialize, Serialize};
2use crate::{Result, BuilderError};
3use std::path::Path;
4
5/// Configuration for the reputation calculator
6/// 
7/// Controls how reputation scores are calculated, including
8/// confidence growth rate and prior score parameters.
9/// 
10/// # Example
11/// 
12/// ```
13/// use reputation_core::CalculatorConfig;
14/// 
15/// let config = CalculatorConfig {
16///     confidence_k: 20.0,  // Slower confidence growth
17///     prior_base: 60.0,    // Higher starting score
18///     prior_max: 90.0,     // Higher maximum prior
19/// };
20/// ```
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct CalculatorConfig {
23    /// Confidence growth parameter (k in the formula)
24    /// Higher values = slower confidence growth
25    /// Default: 15.0
26    #[serde(default = "default_confidence_k")]
27    pub confidence_k: f64,
28    
29    /// Base prior score for all agents
30    /// Default: 50.0
31    #[serde(default = "default_prior_base")]
32    pub prior_base: f64,
33    
34    /// Maximum possible prior score
35    /// Default: 80.0
36    #[serde(default = "default_prior_max")]
37    pub prior_max: f64,
38}
39
40fn default_confidence_k() -> f64 { 15.0 }
41fn default_prior_base() -> f64 { 50.0 }
42fn default_prior_max() -> f64 { 80.0 }
43
44impl Default for CalculatorConfig {
45    fn default() -> Self {
46        Self {
47            confidence_k: default_confidence_k(),
48            prior_base: default_prior_base(),
49            prior_max: default_prior_max(),
50        }
51    }
52}
53
54impl CalculatorConfig {
55    /// Load configuration from a JSON file
56    /// 
57    /// # Example
58    /// 
59    /// ```no_run
60    /// use reputation_core::CalculatorConfig;
61    /// use std::path::Path;
62    /// 
63    /// let config = CalculatorConfig::from_file(Path::new("config/calculator.json"))
64    ///     .expect("Failed to load config");
65    /// ```
66    pub fn from_file(path: &Path) -> Result<Self> {
67        let content = std::fs::read_to_string(path)
68            .map_err(|e| BuilderError::InvalidConfig(format!("Failed to read config file: {}", e)))?;
69        
70        serde_json::from_str(&content)
71            .map_err(|e| BuilderError::InvalidConfig(format!("Failed to parse config JSON: {}", e)).into())
72    }
73    
74    /// Save configuration to a JSON file
75    /// 
76    /// # Example
77    /// 
78    /// ```no_run
79    /// use reputation_core::CalculatorConfig;
80    /// use std::path::Path;
81    /// 
82    /// let config = CalculatorConfig::default();
83    /// config.to_file(Path::new("config/calculator.json"))
84    ///     .expect("Failed to save config");
85    /// ```
86    pub fn to_file(&self, path: &Path) -> Result<()> {
87        let content = serde_json::to_string_pretty(self)
88            .map_err(|e| BuilderError::InvalidConfig(format!("Failed to serialize config: {}", e)))?;
89        
90        std::fs::write(path, content)
91            .map_err(|e| BuilderError::InvalidConfig(format!("Failed to write config file: {}", e)).into())
92    }
93}
94
95/// Configuration presets for common scenarios
96pub mod presets {
97    use super::CalculatorConfig;
98    
99    /// Fast confidence growth for testing environments
100    pub fn testing() -> CalculatorConfig {
101        CalculatorConfig {
102            confidence_k: 5.0,
103            prior_base: 50.0,
104            prior_max: 80.0,
105        }
106    }
107    
108    /// Conservative configuration with slow confidence growth
109    pub fn conservative() -> CalculatorConfig {
110        CalculatorConfig {
111            confidence_k: 30.0,
112            prior_base: 60.0,
113            prior_max: 80.0,
114        }
115    }
116    
117    /// Aggressive configuration with fast confidence growth
118    pub fn aggressive() -> CalculatorConfig {
119        CalculatorConfig {
120            confidence_k: 10.0,
121            prior_base: 40.0,
122            prior_max: 90.0,
123        }
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130    
131    #[test]
132    fn test_default_config() {
133        let config = CalculatorConfig::default();
134        assert_eq!(config.confidence_k, 15.0);
135        assert_eq!(config.prior_base, 50.0);
136        assert_eq!(config.prior_max, 80.0);
137    }
138    
139    #[test]
140    fn test_presets() {
141        let testing = presets::testing();
142        assert_eq!(testing.confidence_k, 5.0);
143        
144        let conservative = presets::conservative();
145        assert_eq!(conservative.confidence_k, 30.0);
146        
147        let aggressive = presets::aggressive();
148        assert_eq!(aggressive.confidence_k, 10.0);
149    }
150    
151    #[test]
152    fn test_config_serialization() {
153        let config = CalculatorConfig {
154            confidence_k: 25.0,
155            prior_base: 55.0,
156            prior_max: 85.0,
157        };
158        
159        let json = serde_json::to_string(&config).unwrap();
160        let deserialized: CalculatorConfig = serde_json::from_str(&json).unwrap();
161        
162        assert_eq!(config.confidence_k, deserialized.confidence_k);
163        assert_eq!(config.prior_base, deserialized.prior_base);
164        assert_eq!(config.prior_max, deserialized.prior_max);
165    }
166    
167    #[test]
168    fn test_partial_config_deserialization() {
169        // Only specify one field, others should use defaults
170        let json = r#"{"confidence_k": 25.0}"#;
171        let config: CalculatorConfig = serde_json::from_str(json).unwrap();
172        
173        assert_eq!(config.confidence_k, 25.0);
174        assert_eq!(config.prior_base, 50.0);  // default
175        assert_eq!(config.prior_max, 80.0);   // default
176    }
177}