{"record":{"id":"37dfa159514df3bb","repo":"affaan-m/ECC","slug":"health-evidence-does-not-match-candidate-and-evalu","errorCode":null,"errorMessage":"health evidence does not match candidate and evaluator","messagePattern":"health evidence does not match candidate and evaluator","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/session/store.rs","lineNumber":5476,"sourceCode":"        policy: PromotionPolicy,\n        evidence_ref: &str,\n        health_evidence: &HealthEvidenceSnapshot,\n        health_check: F,\n    ) -> Result<HarnessPromotionOutcome>\n    where\n        F: FnOnce(&str) -> Result<bool>,\n    {\n        if candidate_id.len() != 64\n            || baseline_id.len() != 64\n            || evaluator != \"recorded-v1\"\n            || evidence_ref.trim().is_empty()\n            || evidence_ref.len() > 4096\n        {\n            anyhow::bail!(\"valid candidate ids, recorded-v1 evaluator, and bounded evidence reference are required\");\n        }\n        health_evidence.verify()?;\n        if health_evidence.candidate_id != candidate_id || health_evidence.evaluator != evaluator {\n            anyhow::bail!(\"health evidence does not match candidate and evaluator\");\n        }\n        let comparison = policy.compare(samples)?;\n        let tx = self.conn.unchecked_transaction()?;\n        let stored_candidate_id = Self::resolve_harness_candidate_id(&tx, candidate_id)?;\n        let stored_baseline_id = Self::resolve_harness_candidate_id(&tx, baseline_id)?;\n        let active: String = tx\n            .query_row(\n                \"SELECT candidate_id FROM active_harness_config WHERE slot = 'default'\",\n                [],\n                |row| row.get(0),\n            )\n            .context(\"no active baseline configuration\")?;\n        if active != stored_baseline_id {\n            anyhow::bail!(\"baseline is not the active harness configuration\");\n        }\n        let now = chrono::Utc::now().to_rfc3339();\n        if !comparison.passed {\n            tx.execute(\"INSERT INTO harness_evaluations (candidate_id, baseline_id, evaluator, samples_json, policy_json, comparison_json, evidence_ref, legacy_unverifiable, created_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, 0, ?8)\", rusqlite::params![stored_candidate_id, stored_baseline_id, evaluator, serde_json::to_string(samples)?, serde_json::to_string(&policy)?, serde_json::to_string(&comparison)?, evidence_ref, now])?;","sourceCodeStart":5458,"sourceCodeEnd":5494,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/session/store.rs#L5458-L5494","documentation":"Before evaluating a promotion, the store verifies the supplied HealthEvidenceSnapshot (signature/integrity via verify()) and checks that its candidate_id and evaluator fields match the promotion call's arguments. A mismatch means the health snapshot attests a different candidate or evaluator than the promotion being attempted, so the operation is refused to keep evidence and action aligned.","triggerScenarios":"Calling evaluate_promote_and_health_check with a health_evidence snapshot built for a different candidate_id or evaluator string than the arguments passed in, or with a snapshot that fails verify() (raising the verify error, not this one).","commonSituations":"Reusing a cached health snapshot from a previous evaluation of another candidate; swapping the evaluator label after the snapshot was created (e.g. changing \"recorded-v1\" casing or suffix); copy-paste mistakes when wiring multiple promotions in parallel.","solutions":["Regenerate the HealthEvidenceSnapshot for the exact candidate_id and evaluator being promoted in this call.","Compare health_evidence.candidate_id and health_evidence.evaluator against your arguments before calling to catch mismatches early.","If promoting multiple candidates, keep snapshots keyed per (candidate_id, evaluator) rather than sharing one snapshot.","Ensure verify() passes first; a failed verify indicates tampering/corruption and needs a fresh snapshot, not a field patch."],"exampleFix":"// before: snapshot from previous run for another candidate\nlet snapshot = previous_snapshot; // candidate_id = \"old...\"\nstore.evaluate_promote_and_health_check(&new_cand, &base, \"recorded-v1\", ..., &snapshot, ...)?;\n\n// after\nlet snapshot = HealthEvidenceSnapshot::build(&new_cand, \"recorded-v1\", asserted_healthy)?;\nsnapshot.verify()?;\nstore.evaluate_promote_and_health_check(&new_cand, &base, \"recorded-v1\", ..., &snapshot, ...)?;","handlingStrategy":"validation","validationCode":"// Verify snapshot alignment before calling the API\nhealth_evidence.verify()?;\nanyhow::ensure!(health_evidence.candidate_id == candidate_id, \"snapshot is for a different candidate\");\nanyhow::ensure!(health_evidence.evaluator == evaluator, \"snapshot is for a different evaluator\");","typeGuard":"fn matches_promotion(snapshot: &HealthEvidenceSnapshot, candidate_id: &str, evaluator: &str) -> bool {\n    snapshot.candidate_id == candidate_id && snapshot.evaluator == evaluator\n}","tryCatchPattern":"match store.evaluate_promote_and_health_check(...) {\n    Err(e) if e.to_string().contains(\"health evidence does not match\") => {\n        // rebuild the snapshot for this candidate/evaluator and retry once\n    }\n    other => other?,\n}","preventionTips":["Create HealthEvidenceSnapshot fresh for every promotion call; never share across candidates","Key snapshots by (candidate_id, evaluator) in caches","Always call verify() on the snapshot yourself before invoking the API"],"tags":["validation","evidence","mismatch","rust"],"backgroundTag":"invalid-argument-value","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"}