Skip to content

fix(resurrect): skip empty-session snapshots and preserve last pointer#27

Open
TrvoDK wants to merge 1 commit into
psmux:mainfrom
TrvoDK:fix/resurrect-skip-empty-snapshot
Open

fix(resurrect): skip empty-session snapshots and preserve last pointer#27
TrvoDK wants to merge 1 commit into
psmux:mainfrom
TrvoDK:fix/resurrect-skip-empty-snapshot

Conversation

@TrvoDK

@TrvoDK TrvoDK commented Jun 23, 2026

Copy link
Copy Markdown

Part of #26.

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 is 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.

This adds a guard after the session-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 — 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, the client-detached save hook, and the manual Prefix+Ctrl-s binding), 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 via PATHEXT + redirected $env:USERPROFILE; needs no server and no real psmux binary, unlike the existing test_resurrect*.ps1 which wipe the real ~/.psmux/resurrect). Asserts: an empty capture writes nothing and leaves last byte-identical (both with a prior good last and 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.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant