fix(resurrect): skip empty-session snapshots and preserve last pointer#27
Conversation
save.ps1 could persist a 0-session snapshot and repoint ~/.psmux/resurrect/last to it. When no server is running, list-sessions returns empty (psmux exits 0 with no output), so the capture was empty -- but the snapshot was still written and last repointed, and the 20-slot rotation then evicted the good snapshots, silently destroying the ability to resurrect. Add a guard after the capture loop: if 0 sessions were captured, skip the write entirely and leave last untouched. A 0-session capture means the server is down (psmux/tmux destroys the server when its last session is gone), so an empty snapshot is never worth persisting. The guard sits before the dedup/write/rotation and protects every caller of save.ps1 (the continuum auto-save loop, the client-detached hook, and the manual Prefix+Ctrl-s binding). Known limitation (follow-up): a partial capture -- a server mid-startup reporting some-but-not-all sessions -- has >=1 session so it passes this guard and is still written. Closing that needs an expected-session-count signal the script does not have today. Tests: tests/test_resurrect_guard.ps1 -- hermetic (fake-psmux shim + redirected USERPROFILE; needs no server and no real binary, unlike the existing test_resurrect*.ps1 which wipe the real resurrect dir). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Hey @TrvoDK, thanks for chasing this one down properly. I reproduced #26 hermetically before even opening this diff (sandboxed Then I checked out this branch and reran the exact same scenario against your patched The placement of the guard (after the capture loop, before dedup and before the Merging this now as the keystone fix for #26. Great work, thank you. |
Part of #26.
save.ps1could persist a 0-session snapshot and repoint~/.psmux/resurrect/lastto it. When no server is running,list-sessionsreturns empty (psmux exits 0 with no output), so the capture is empty — but the snapshot was still written andlastrepointed, and the 20-slot rotation then evicted the good snapshots, silently destroying the ability to resurrect.This adds a guard after the session-capture loop: if 0 sessions were captured, skip the write entirely and leave
lastuntouched. A 0-session capture means the server is down (psmux/tmux destroys the server when its last session is gone), so an empty snapshot is never worth persisting — and persisting it is actively harmful. The guard sits before the dedup/write/rotation.It protects every caller of
save.ps1(the continuum auto-save loop, theclient-detachedsave hook, and the manualPrefix+Ctrl-sbinding), so the invariant "never persist a meaningless snapshot" lives with the writer rather than being re-implemented per caller.Known limitation (follow-up, not fixed here): a partial capture — a server mid-startup reporting some-but-not-all sessions — is not covered; that snapshot has ≥1 session so it passes this guard and is written. Closing that needs an expected-session-count signal the script doesn't have today.
Tests:
tests/test_resurrect_guard.ps1— hermetic (fake-psmux shim resolved viaPATHEXT+ redirected$env:USERPROFILE; needs no server and no real psmux binary, unlike the existingtest_resurrect*.ps1which wipe the real~/.psmux/resurrect). Asserts: an empty capture writes nothing and leaveslastbyte-identical (both with a prior goodlastand on a virgin dir, so the guard is exercised independently of the dedup); a live session still writes (no false skip); and a characterization test pinning the known partial-capture gap.Validation: there is no CI in this repo and the live E2E harness is destructive against the real resurrect dir, so this was validated via the hermetic sandbox test above + code reasoning — not a CI run.