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

  1. Regenerate the health evidence snapshot at promotion time so asserted_healthy matches the current health check result.
  2. Make the health_check closure probe the same target/endpoint/environment the snapshot was asserted against.
  3. Investigate why the candidate is unhealthy (check logs of the health probe); the rollback is intentional — fix the candidate before re-promoting.
  4. 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

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


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)