affaan-m/ECC · error
health check result does not match persisted assertion
Error message
health check result does not match persisted assertion
What it means
After the promotion update succeeds, the store runs the caller-supplied health_check and compares its boolean result with the asserted_healthy value recorded in the pre-verified health evidence snapshot. If the live check disagrees with the persisted assertion (or the check errors in a way that changes the outcome handling), the promotion is treated as unhealthy and rolled back — this error surfaces the assertion/result disagreement.
Solutions
- Regenerate the health evidence snapshot at promotion time so asserted_healthy matches the current health check result.
- Make the health_check closure probe the same target/endpoint/environment the snapshot was asserted against.
- Investigate why the candidate is unhealthy (check logs of the health probe); the rollback is intentional — fix the candidate before re-promoting.
- If the check is flaky, stabilize it (retries with backoff inside the closure) so results are deterministic at promotion time.
Example fix
// before: stale assertion let snapshot = build_snapshot(cand, "recorded-v1", /*asserted_healthy*/ true)?; store.evaluate_promote_and_health_check(&cand, &base, "recorded-v1", ..., &snapshot, |id| Ok(probe(id)))?; // after: assert from a fresh probe so they agree let healthy_now = probe(&cand)?; let snapshot = build_snapshot(&cand, "recorded-v1", healthy_now)?; store.evaluate_promote_and_health_check(&cand, &base, "recorded-v1", ..., &snapshot, |id| Ok(probe(id)))?;
Defensive patterns
Strategy: try-catch
Validate before calling
// Assert health from a probe taken immediately before the call so the // snapshot's asserted_healthy matches what health_check will return let healthy_now = run_health_probe(&candidate_id)?; let snapshot = HealthEvidenceSnapshot::build(&candidate_id, "recorded-v1", healthy_now)?; snapshot.verify()?;
Try / catch
match outcome {
Ok(o) if o.rolled_back => {
// promotion applied but rolled back due to assertion mismatch:
// inspect health_check output, fix the candidate, rebuild snapshot, retry
}
Err(e) if e.to_string().contains("health check result does not match") => {
// rebuild snapshot from a fresh probe and re-attempt once
}
other => other?,
} Prevention
- Generate health evidence at promotion time, not ahead of time
- Point health_check and the evidence snapshot at the same environment/endpoint
- Stabilize flaky probes (internal retries/backoff) so results are deterministic
- Treat rollback as the intended safety behavior — investigate candidate health before re-promoting
When it happens
Trigger: Calling evaluate_promote_and_health_check with asserted_healthy=true in the snapshot while the supplied health_check closure returns false (or vice versa), or the health_check closure itself returns Err which then conflicts with the recorded assertion during result reconciliation.
Common situations: Health evidence captured earlier (asserting healthy) but the service degraded by promotion time; a health_check closure hitting a different environment/endpoint than the one the snapshot was generated against; flaky health probes returning a different answer than at evidence-creation time.
Related errors
- health evidence does not match candidate and evaluator
- exactly one candidate-keyed health assertion is required
- agent profile inheritance cycle
- an active harness configuration already exists
- atomic promotion compare-and-swap failed
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/39a2e29c9daecb47.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/session/store.rs:5511
if !comparison.passed {
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])?;
let evaluation_id = tx.last_insert_rowid();
tx.execute("INSERT INTO harness_eval_audit (event_type, candidate_id, prior_candidate_id, evaluation_id, evidence_ref, legacy_unverifiable, created_at) VALUES ('promotion_rejected', ?1, ?2, ?3, ?4, 0, ?5)", rusqlite::params![stored_candidate_id, stored_baseline_id, evaluation_id, evidence_ref, now])?;
tx.commit()?;
return Ok(HarnessPromotionOutcome {
evaluation_id: Some(evaluation_id),
promoted: false,
rolled_back: false,
failures: comparison.failures,
});
}
let changed = tx.execute("UPDATE active_harness_config SET candidate_id = ?1, updated_at = ?2 WHERE slot = 'default' AND candidate_id = ?3", rusqlite::params![stored_candidate_id, now, stored_baseline_id])?;
if changed != 1 {
anyhow::bail!("atomic promotion compare-and-swap failed");
}
let health_result = health_check(candidate_id).and_then(|healthy| {
if healthy != health_evidence.asserted_healthy {
anyhow::bail!("health check result does not match persisted assertion");
}
Ok(healthy)
});
let healthy = matches!(health_result, Ok(true));
let event_type = match &health_result {
Ok(true) => "promoted",
Ok(false) => "promotion_rolled_back",
Err(_) => "health_check_error_rolled_back",
};
let health_check_status = match &health_result {
Ok(true) => "healthy",
Ok(false) => "unhealthy",
Err(_) => "error",
};
if !healthy {
let restored = tx.execute("UPDATE active_harness_config SET candidate_id = ?1, updated_at = ?2 WHERE slot = 'default' AND candidate_id = ?3", rusqlite::params![stored_baseline_id, now, stored_candidate_id])?;
if restored != 1 {
anyhow::bail!("atomic rollback compare-and-swap failed");View on GitHub (pinned to 8321021c54)