use car_eventlog::harness_metrics::HarnessMetrics;
use car_memgine::harness_evolution::{
EvolutionAgent, EvolutionConfig, Governance, HarnessConfig, HarnessMutation, PromotionDecision,
};
fn parse_metrics(json: &str, what: &str) -> Result<HarnessMetrics, String> {
serde_json::from_str(json).map_err(|e| format!("invalid {what} metrics JSON: {e}"))
}
fn agent(config_json: Option<&str>) -> Result<EvolutionAgent, String> {
match config_json {
Some(c) => {
let config: EvolutionConfig = serde_json::from_str(c)
.map_err(|e| format!("invalid evolution config JSON: {e}"))?;
Ok(EvolutionAgent::with_config(config))
}
None => Ok(EvolutionAgent::new()),
}
}
pub fn diagnose(metrics_json: &str, config_json: Option<&str>) -> Result<String, String> {
let metrics = parse_metrics(metrics_json, "harness")?;
let mutations = agent(config_json)?.diagnose(&metrics);
serde_json::to_string(&mutations).map_err(|e| e.to_string())
}
pub fn evaluate(
mutation_json: &str,
baseline_json: &str,
candidate_json: &str,
config_json: Option<&str>,
) -> Result<String, String> {
let mutation: HarnessMutation =
serde_json::from_str(mutation_json).map_err(|e| format!("invalid mutation JSON: {e}"))?;
let baseline = parse_metrics(baseline_json, "baseline")?;
let candidate = parse_metrics(candidate_json, "candidate")?;
let decision = agent(config_json)?.evaluate(&mutation, &baseline, &candidate);
serde_json::to_string(&decision).map_err(|e| e.to_string())
}
pub fn apply(
config_json: &str,
mutation_json: &str,
decision_json: Option<&str>,
human_approved: bool,
) -> Result<String, String> {
let mut config: HarnessConfig =
serde_json::from_str(config_json).map_err(|e| format!("invalid config JSON: {e}"))?;
let mutation: HarnessMutation =
serde_json::from_str(mutation_json).map_err(|e| format!("invalid mutation JSON: {e}"))?;
let governance = if human_approved {
Governance::HumanApproved
} else {
let dj = decision_json
.ok_or("non-approved apply requires a decision_json (a PromotionDecision)")?;
let decision: PromotionDecision =
serde_json::from_str(dj).map_err(|e| format!("invalid decision JSON: {e}"))?;
Governance::Promoted(decision)
};
let rollback = config.apply(&mutation, governance)?;
serde_json::to_string(&serde_json::json!({ "config": config, "rollback": rollback }))
.map_err(|e| e.to_string())
}