{"record":{"id":"6f2f2ad958b15d50","repo":"affaan-m/ECC","slug":"candidate-content-address-or-canonical-configurati","errorCode":null,"errorMessage":"candidate content address or canonical configuration is invalid","messagePattern":"candidate content address or canonical configuration is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ecc2/src/harness_eval.rs","lineNumber":217,"sourceCode":"        }\n        let artifact = serde_json::to_string(&CanonicalCandidateArtifact {\n            config: serde_json::from_str(&canonical_config)?,\n            trace_refs: &trace_refs,\n            evidence_refs: &evidence_refs,\n        })?;\n        let id = sha256_hex(artifact.as_bytes());\n        Ok(Self {\n            id,\n            canonical_config,\n            trace_refs,\n            evidence_refs,\n        })\n    }\n\n    pub fn verify_integrity(&self) -> Result<()> {\n        self.verify_persisted_id(&self.id)?;\n        if self.id != self.id_for_v2()? {\n            bail!(\"candidate content address or canonical configuration is invalid\");\n        }\n        Ok(())\n    }\n\n    pub fn legacy_id(&self) -> String {\n        sha256_hex(self.canonical_config.as_bytes())\n    }\n\n    pub fn verify_persisted_id(&self, persisted_id: &str) -> Result<()> {\n        let value: Value = serde_json::from_str(&self.canonical_config)?;\n        let rebuilt = Self::new(value, self.trace_refs.clone(), self.evidence_refs.clone())?;\n        let is_v1 = persisted_id == self.legacy_id();\n        let is_v2 = persisted_id == rebuilt.id;\n        if rebuilt.canonical_config != self.canonical_config\n            || (!is_v1 && !is_v2)\n            || (is_v2\n                && (rebuilt.trace_refs != self.trace_refs\n                    || rebuilt.evidence_refs != self.evidence_refs))","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/ecc2/src/harness_eval.rs#L199-L235","documentation":"`CandidateSpec::verify_integrity` recomputes the content address for the current canonical configuration and compares it with the stored/persisted `id`. If the stored id does not match the recomputed id (`self.id != self.id_for_v2()`), the candidate's identity and its content disagree — the record was corrupted, produced by a different algorithm version, or mutated after persistence. The error is a checksum-mismatch-style integrity failure surfacing at read/verification time.","triggerScenarios":"Calling `verify_integrity()` (directly or via `record_harness_candidate`) on a persisted CandidateSpec whose `id` field does not equal `id_for_v2()` computed from its current `canonical_config`, `trace_refs`, and `evidence_refs`.","commonSituations":"Manually editing a persisted candidate JSON file after it was written; old records persisted with a legacy hashing scheme (`legacy_id` = sha256 of canonical config alone) being verified under the v2 scheme; a migration or partial write that changed canonical_config without recomputing the id; copying a candidate record between environments where content differed.","solutions":["Regenerate the candidate: rebuild the CandidateSpec from the current config via `CandidateSpec::new` and re-persist it so id and content are recomputed together.","If the record is a legacy one, re-migrate it: compute `id_for_v2()` from its canonical_config and update the stored id (or use `legacy_id()` for old-scheme records).","Diff the persisted canonical_config against what was originally submitted to find what mutated after the id was written.","Do not hand-edit persisted candidate files; treat them as immutable content-addressed artifacts and delete+recreate instead."],"exampleFix":"// before: stale id after config was edited on disk\nlet spec: CandidateSpec = load_candidate(\"candidates/abc.json\")?;\nspec.verify_integrity()?; // fails: id != id_for_v2()\n\n// after: rebuild so identity matches content\nlet config = serde_json::from_str(&spec_raw.config)?;\nlet spec = CandidateSpec::new(config, spec_raw.trace_refs, spec_raw.evidence_refs)?;\nspec.verify_integrity()?; // passes","handlingStrategy":"try-catch","validationCode":"fn integrity_ok(spec: &CandidateSpec) -> bool {\n    spec.id == spec.id_for_v2().unwrap_or_default()\n}","typeGuard":"fn is_valid_candidate(spec: &CandidateSpec) -> bool {\n    spec.verify_integrity().is_ok()\n}","tryCatchPattern":"match spec.verify_integrity() {\n    Ok(()) => use_spec(spec),\n    Err(e) if e.to_string().contains(\"content address\") => {\n        // corrupted or legacy record: rebuild from source config\n        let rebuilt = rebuild_and_persist(&spec.canonical_config)?;\n        use_spec(&rebuilt)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Treat persisted candidate files as immutable; never edit canonical_config in place.","Run a migration pass after upgrading hashing schemes (legacy_id -> v2 id) so old records match the new algorithm.","Recompute the id in the same transaction/write as any content change.","Verify integrity immediately after load, before using the candidate in evaluations."],"tags":["integrity","checksum","content-addressing","persistence","rust"],"backgroundTag":"checksum-mismatch","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"}