{"record":{"id":"157838a9b22a4a04","repo":"affaan-m/ECC","slug":"health-evidence-does-not-match-promoted-candidate","errorCode":null,"errorMessage":"health evidence does not match promoted candidate","messagePattern":"health evidence does not match promoted candidate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/harness_eval.rs","lineNumber":447,"sourceCode":"    fn evaluate(&mut self, candidate_id: &str, seed: u64) -> Result<f64> {\n        self.calls.push((candidate_id.to_string(), seed));\n        let score = *self\n            .scores\n            .get(&(candidate_id.to_string(), seed))\n            .with_context(|| format!(\"missing recorded score for {candidate_id} seed {seed}\"))?;\n        if !score.is_finite() || !(0.0..=1.0).contains(&score) {\n            bail!(\"score must be finite and between 0 and 1\");\n        }\n        Ok(score)\n    }\n\n    fn health_check(&mut self, candidate_id: &str) -> Result<bool> {\n        if self\n            .health_candidate\n            .as_deref()\n            .is_some_and(|expected| expected != candidate_id)\n        {\n            bail!(\"health evidence does not match promoted candidate\");\n        }\n        Ok(self.health_ok)\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]\npub struct PairedSample {\n    pub seed: u64,\n    pub candidate_score: f64,\n    pub baseline_score: f64,\n}\n\npub fn evaluate_paired(\n    evaluator: &mut dyn Evaluator,\n    candidate_id: &str,\n    baseline_id: &str,\n    seeds: &[u64],\n) -> Result<Vec<PairedSample>> {","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/harness_eval.rs#L429-L465","documentation":"health_check verifies that the recorded health evidence belongs to the candidate actually being promoted. This error is thrown when evaluate_promote_and_health_check is called for a candidate id that differs from the single candidate id recorded in the evidence's health map. The recorded evaluator refuses to treat health evidence for a different candidate as proof for this promotion.","triggerScenarios":"Calling evaluate_promote_and_health_check with a candidate_id string that does not exactly match the key stored in the RecordedEvidence health map (e.g. promoting \"candidate-b\" while health evidence was recorded for \"candidate-a\").","commonSituations":"Mixing up candidate ids when multiple candidates share an evidence file; ids differing by whitespace/case/encoding; replaying evidence recorded in a previous run against a newly generated candidate id.","solutions":["Promote the same candidate id that owns the single health entry in the recorded evidence.","Re-record or regenerate the evidence with health keyed to the candidate you intend to promote.","Compare ids for exact string equality, including case and trailing whitespace, before calling evaluate_promote_and_health_check.","If comparing multiple candidates, use separate RecordedEvaluator instances, one per candidate's evidence."],"exampleFix":"// before\nlet eval = RecordedEvaluator::from_evidence(evidence_for_candidate_a)?;\nlet result = eval.evaluate_promote_and_health_check(\"candidate-b\", ...)?; // mismatch bails\n\n// after\nlet eval = RecordedEvaluator::from_evidence(evidence_for_candidate_a)?;\nlet result = eval.evaluate_promote_and_health_check(\"candidate-a\", ...)?; // matches health key","handlingStrategy":"type-guard","validationCode":"let (health_candidate, _) = evidence.health.iter().next().unwrap();\nassert_eq!(health_candidate, candidate_to_promote);","typeGuard":"fn health_matches(evidence: &RecordedEvidence, candidate_id: &str) -> bool {\n    evidence.health.len() == 1 && evidence.health.contains_key(candidate_id)\n}","tryCatchPattern":null,"preventionTips":["Key health evidence to the exact id string you will pass to evaluate_promote_and_health_check.","Use one RecordedEvaluator per candidate; never share evidence across promotions.","Log candidate ids at record time to catch case/whitespace mismatches early."],"tags":["validation","candidate-mismatch","promotion"],"backgroundTag":"invalid-state-transition","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}