{"record":{"id":"d3b65828725ada7c","repo":"affaan-m/ECC","slug":"atomic-promotion-compare-and-swap-failed","errorCode":null,"errorMessage":"atomic promotion compare-and-swap failed","messagePattern":"atomic promotion compare-and-swap failed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"ecc2/src/session/store.rs","lineNumber":5507,"sourceCode":"        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])?;\n            let evaluation_id = tx.last_insert_rowid();\n            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])?;\n            tx.commit()?;\n            return Ok(HarnessPromotionOutcome {\n                evaluation_id: Some(evaluation_id),\n                promoted: false,\n                rolled_back: false,\n                failures: comparison.failures,\n            });\n        }\n        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])?;\n        if changed != 1 {\n            anyhow::bail!(\"atomic promotion compare-and-swap failed\");\n        }\n        let health_result = health_check(candidate_id).and_then(|healthy| {\n            if healthy != health_evidence.asserted_healthy {\n                anyhow::bail!(\"health check result does not match persisted assertion\");\n            }\n            Ok(healthy)\n        });\n        let healthy = matches!(health_result, Ok(true));\n        let event_type = match &health_result {\n            Ok(true) => \"promoted\",\n            Ok(false) => \"promotion_rolled_back\",\n            Err(_) => \"health_check_error_rolled_back\",\n        };\n        let health_check_status = match &health_result {\n            Ok(true) => \"healthy\",\n            Ok(false) => \"unhealthy\",\n            Err(_) => \"error\",\n        };","sourceCodeStart":5489,"sourceCodeEnd":5525,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/ecc2/src/session/store.rs#L5489-L5525","documentation":"Promotion uses an atomic compare-and-swap: UPDATE active_harness_config SET candidate_id=new WHERE slot='default' AND candidate_id=baseline. If exactly one row is not updated (changed != 1), the baseline changed between the read and the write — a concurrent mutation won the race.","triggerScenarios":"Between promote_harness's baseline check and its CAS update, another writer changed active_harness_config.candidate_id for slot 'default' (concurrent promotion or rollback).","commonSituations":"Two promoters racing on the same store; a rollback interleaving between read and CAS; the active row was deleted by a reset.","solutions":["Retry the whole promotion after re-reading the active baseline (optimistic concurrency).","Serialize promotions with an external lock/mutex so only one writer mutates active_harness_config at a time.","Surface a distinct 'concurrent modification, please retry' error to the caller rather than a generic failure."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// CAS failures are inherently racy; validate by re-reading immediately before retry.\nfn try_promote_with_retry(store: &Store, candidate_id: &str, max_attempts: u8) -> Result<HarnessPromotionOutcome> {\n    for _ in 0..max_attempts {\n        let baseline = store.active_harness_id()?.ok_or_else(|| anyhow::anyhow!(\"no active\"))?;\n        match store.promote_harness(candidate_id, &baseline, /* ... */) {\n            Ok(out) => return Ok(out),\n            Err(e) if e.to_string().contains(\"atomic promotion compare-and-swap failed\") => continue,\n            Err(e) => return Err(e),\n        }\n    }\n    anyhow::bail!(\"promotion lost the CAS race {max_attempts} times\");\n}","typeGuard":null,"tryCatchPattern":"loop {\n    let baseline = store.active_harness_id()?.ok_or_else(|| anyhow::anyhow!(\"no active\"))?;\n    match store.promote_harness(&candidate_id, &baseline, ...) {\n        Ok(out) => break Ok(out),\n        Err(e) if e.to_string().contains(\"atomic promotion compare-and-swap failed\") => continue,\n        Err(e) => break Err(e),\n    }\n}","preventionTips":["Serialize harness mutations with an external mutex so the CAS rarely races.","Bound the retry count and surface a clear 'concurrent modification' error when exhausted.","Re-read the active baseline on every attempt; never assume it is stable across attempts."],"tags":["rust","sqlite","harness","concurrency","cas"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}