{"record":{"id":"f201405cff1730e7","repo":"Hmbown/CodeWhale","slug":"compaction-coverage-floor-checkpoint-receipt-was-dropped","errorCode":null,"errorMessage":"Compaction coverage floor: checkpoint receipt was dropped; history was not replaced.","messagePattern":"Compaction coverage floor: checkpoint receipt was dropped; history was not replaced\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/compaction/last_round.rs","lineNumber":455,"sourceCode":"    });\n    if !kept {\n        anyhow::bail!(\"Compaction coverage floor: {label} was dropped; history was not replaced.\");\n    }\n    Ok(())\n}\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,","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/compaction/last_round.rs#L437-L473","documentation":"The survival contract requires exactly one compaction checkpoint receipt message in the replacement history. Zero receipts means the compaction marker/receipt was dropped; more than one means prior summaries were duplicated. Either way history is not replaced. (This entry covers the zero-receipt case.)","triggerScenarios":"`validate_survival_contract` (called by `build_replacement_history` and tests) counts messages passing `is_compaction_checkpoint_message` in the replacement and finds zero.","commonSituations":"A rewrite builds the replacement from raw summarized content and forgets to append the checkpoint receipt message; refactor renames/restructures the receipt so `is_compaction_checkpoint_message` no longer matches it.","solutions":["Append the compaction checkpoint receipt message to the replacement history before validation.","Ensure `is_compaction_checkpoint_message` still matches the receipt structure after any schema change.","Check `build_replacement_history` emits exactly one receipt (fix the >1 duplicate branch separately).","Run `survival_contract_rejects_dropped_anchors_and_receipts` and the fixture matrix to reproduce."],"exampleFix":"// before: receipt lost in rewrite\nlet replacement = summarized_history;\n// after\nlet replacement = [summarized_history, vec![checkpoint_receipt_message]].concat();","handlingStrategy":"validation","validationCode":"fn has_single_receipt(replacement: &[Message]) -> bool {\n    replacement.iter().filter(|m| is_compaction_checkpoint_message(m)).count() == 1\n}","typeGuard":null,"tryCatchPattern":"match compaction::apply_replacement(&replacement) {\n    Err(e) if e.to_string().contains(\"checkpoint receipt\") => keep_original_history(),\n    other => other,\n}","preventionTips":["Always append exactly one checkpoint receipt to every replacement history","Keep is_compaction_checkpoint_message in sync with the receipt schema","Test both zero-receipt and duplicate-receipt paths","Build replacements through build_replacement_history so the receipt is never forgotten"],"tags":["compaction","checkpoint-receipt","survival-contract"],"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"}