ecdbcef7af
`archive_and_compact()` is atomic: when it raises, every pre-compaction row is still `active = 1` and the compacted set was never inserted. The rotation branch already rolled the live transcript back to `messages_before_compression` in that case, but the in-place branch — the default (`compression_in_place` defaults to True) — did not, so `compress_context()` handed the caller the uncommitted compacted list. That list is marker-swept by `_strip_persistence_markers` (#57491) and the post-commit `stamp_db_persisted_markers` (#98450) never ran, so the next append-only flush treated the whole compacted transcript as new and INSERTed it on top of the rows it was supposed to replace. The active set then held the summary AND the turns it summarized: the next resume reloaded both, the token count went up, preflight fired again, and every failed attempt appended another copy of the protected head plus tail. The in-place rollback mirrors the rotation branch and is gated on `split_status != "in_place_committed"`, which is assigned on the statement immediately after the atomic commit returns, so a committed compaction can never be rolled back into a mismatch of the opposite sign. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EKrRS7LVgyHf2WQkEahSwu