{"record":{"id":"49e5253dfd453242","repo":"Hmbown/CodeWhale","slug":"compaction-coverage-floor-prior-summaries-were-duplicated","errorCode":null,"errorMessage":"Compaction coverage floor: prior summaries were duplicated; history was not replaced.","messagePattern":"Compaction coverage floor: prior summaries were duplicated; history was not replaced\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/compaction/last_round.rs","lineNumber":460,"sourceCode":"}\n\npub(crate) fn validate_survival_contract(\n    original: &[Message],\n    replacement: &[Message],\n    anchors: Option<&str>,\n) -> Result<()> {\n    validate_last_round_coverage(original, replacement)?;\n    let checkpoints = replacement\n        .iter()\n        .filter(|message| is_compaction_checkpoint_message(message))\n        .count();\n    if checkpoints == 0 {\n        anyhow::bail!(\n            \"Compaction coverage floor: checkpoint receipt was dropped; history was not replaced.\"\n        );\n    }\n    if checkpoints > 1 {\n        anyhow::bail!(\n            \"Compaction coverage floor: prior summaries were duplicated; history was not replaced.\"\n        );\n    }\n    if let Some(anchors) = anchors {\n        require_text_survives(replacement, anchors, \"pinned /anchor text\")?;\n    }\n    Ok(())\n}\n\npub(super) fn measure_coverage(\n    original: &[Message],\n    replacement: &[Message],\n    path: CompactionPath,\n    anchors_chars: usize,\n) -> CompactionCoverage {\n    let last_round = last_round_slice(replacement);\n    CompactionCoverage {\n        path,","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/compaction/last_round.rs#L442-L478","documentation":"Thrown by validate_survival_contract when a compaction replacement history does not satisfy the survival contract: it must contain exactly one checkpoint receipt (prior summary), and any pinned /anchor text must survive. The 'duplicated' variant fires when more than one prior summary was carried into the replacement, meaning compaction duplicated summaries instead of replacing history. Compaction must swap old history for the replacement, not copy summaries forward multiple times.","triggerScenarios":"build_replacement_history produced a replacement containing >1 checkpoint receipt while dropping original history; also triggered directly by tests survival_contract_rejects_dropped_anchors_and_receipts and fixture_matrix_enforces_survival_contract to enforce the invariant. Specifically the `checkpoints > 1` branch at last_round.rs:460.","commonSituations":"A compaction implementation bug that appends prior summaries into the new history alongside the original summary; refactoring compaction logic and accidentally keeping both the old summary entry and a newly generated one; fixtures that assemble replacement histories by concatenation.","solutions":["Fix build_replacement_history so it emits exactly one checkpoint receipt for prior summaries.","Ensure the replacement replaces (not appends to) the summarized history — remove the original summary entries before inserting the new one.","Run the fixture matrix / survival contract tests to confirm exactly one checkpoint survives per replacement."],"exampleFix":"// before\nreplacement.push(old_summary_receipt);\nreplacement.push(new_summary_receipt);\n// after\nreplacement.clear_summarized_history();\nreplacement.push(new_summary_receipt); // single checkpoint receipt","handlingStrategy":"validation","validationCode":"let checkpoints = replacement.checkpoint_receipts();\nif checkpoints != 1 {\n    return Err(format!(\"replacement must carry exactly 1 checkpoint receipt, got {checkpoints}\"));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always clear summarized history before inserting a new summary receipt.","Run the survival-contract fixture tests after any compaction change."],"tags":["compaction","internal-invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}