# Upgrade Guide — v0.28.39

<!-- bump: patch -->

## What Changed

**Fix: CompactionSentinel allows re-recovery after a previous recovery finalizes, even within the dedupe window.**

The `recentReports` map, used to dedupe overlapping trigger events from the PreCompact hook, watchdog poll, and recovery-hook endpoint, was only cleared by `stop()` and `clear()`. When a recovery finalized (either `recovered` or `failed`) and the session compacted again within the 60-second dedupe window, the second compaction was silently suppressed — same session, fresh compaction event, no recovery attempt.

Fix: on finalize, schedule the `recentReports[sessionName]` entry to be deleted alongside the `active[sessionName]` entry (after the keep-window). A second compaction on the same session is now always eligible for a fresh recovery once the first one has finalized and its keep-window elapsed.

## What to Tell Your User

- **Back-to-back session recoveries work now**: "If my session goes through compaction twice in quick succession, I recover from the second one the same way I recovered from the first — no silent skipping."

## Summary of New Capabilities

| Capability | How to Use |
|-----------|-----------|
| Re-recovery after finalize | automatic — no config change |

## Evidence

**Reproduction of the failure mode via unit test (tests/unit/CompactionSentinel.test.ts "allows re-recovery after a previous recovery finalizes"):**

The test sets up a recovery that succeeds, waits out the 5-second keep-window, then triggers a second compaction on the same session. It asserts that exactly 2 `compaction:detected` events fire (one per compaction). Before the fix: only 1 event fired — the second report was silently suppressed by the `recentReports` timestamp from the first. After the fix: both fire. 16/16 CompactionSentinel tests pass.

**Not reproduced in production** — this is a code-audit finding. Triggering it naturally requires two compactions on the same session within a 65-second window (60s dedupe + up to 5s keep-window for a recovered state), which doesn't happen on the current traffic here. The fix is verified against the state machine via the new test; production evidence would require forcing that timing, which is not deterministically reproducible.
