{"record":{"id":"d622097122dd2cc1","repo":"Hmbown/CodeWhale","slug":"compaction-coverage-floor-last-round-assistant-output-was","errorCode":null,"errorMessage":"Compaction coverage floor: last-round assistant output was dropped; history was not replaced.","messagePattern":"Compaction coverage floor: last-round assistant output was dropped; history was not replaced\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/compaction/last_round.rs","lineNumber":403,"sourceCode":"    }\n    // The call, not just its result. Keeping a tool_result whose tool_use was\n    // summarized away leaves an orphaned result that providers reject outright.\n    for id in last_round.iter().copied().flat_map(tool_use_ids) {\n        if !replacement\n            .iter()\n            .any(|message| has_tool_use_id(message, &id))\n        {\n            anyhow::bail!(\n                \"Compaction coverage floor: last-round tool call {id} was dropped; history was not replaced.\"\n            );\n        }\n    }\n    // Match the assistant's actual output. An existential \"some assistant\n    // message survived\" check passed on a replacement whose only assistant\n    // message was the summary the rewrite had just written.\n    for text in last_round.iter().copied().filter_map(assistant_text_of) {\n        if !survives(&text, replacement, assistant_text_of) {\n            anyhow::bail!(\n                \"Compaction coverage floor: last-round assistant output was dropped; history was not replaced.\"\n            );\n        }\n    }\n    if last_round\n        .iter()\n        .any(|message| message.role.is_assistant_like())\n        && !replacement\n            .iter()\n            .any(|message| message.role.is_assistant_like())\n    {\n        anyhow::bail!(\n            \"Compaction coverage floor: last-round assistant output was dropped; history was not replaced.\"\n        );\n    }\n    Ok(())\n}\n","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/compaction/last_round.rs#L385-L421","documentation":"The survival contract matches the assistant's actual output text from the last round. An existential 'some assistant message survived' check was insufficient — a replacement whose only assistant message was the summary itself passed it. This check requires each last-round assistant text to appear in the replacement; otherwise the rewrite is rejected.","triggerScenarios":"`validate_last_round_coverage` finds a last-round assistant text block whose content is not present in any message of the replacement history (per `survives`/`assistant_text_of`).","commonSituations":"A rewrite replaces the last assistant answer with the summary; a naive compaction keeps 'an assistant message' but it is the summary, not the real answer; regression in rewrite code after refactor.","solutions":["Keep the last-round assistant output text verbatim in the replacement history.","Fix the rewrite so the summary does not displace the actual last assistant answer.","Ensure `assistant_text_of` covers all text blocks so validation sees the real output.","Run `coverage_floor_rejects_assistant_output_replaced_by_a_summary` to reproduce."],"exampleFix":"// before: summary replaced the assistant answer\nreplacement = [summary_msg];\n// after\nreplacement = [summary_msg, original_assistant_msg];","handlingStrategy":"validation","validationCode":"fn keeps_assistant_text(last_round: &[Message], replacement: &[Message]) -> bool {\n    last_round.iter().filter_map(assistant_text_of)\n        .all(|t| replacement.iter().any(|m| assistant_text_of(m) == Some(t)))\n}","typeGuard":null,"tryCatchPattern":"match compaction::apply_replacement(&replacement) {\n    Err(e) if e.to_string().contains(\"assistant output was dropped\") => keep_original_history(),\n    other => other,\n}","preventionTips":["Do not replace the last assistant answer with the summary","Check 'some assistant message survived' is not enough — the summary itself counts","Keep real assistant output verbatim in the replacement","Cover this with the assistant-replaced-by-summary test"],"tags":["compaction","coverage-floor","assistant-output"],"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"}