Live sessions: stale-session cleanup, crash recovery and hardening - #196
Merged
Merged
Conversation
Work in progress for the hardening checkpoint; not yet fully verified. Adds per-protocol-version service sockets, recovery that archives live sessions that ended with no window attached (service crash, reboot, exit while detached), a lost-connection note, a live-session limit, idle age in /resume, and a real-process hardening test suite.
…y, docs Treat a service that drops the connection while exiting (closed, EPIPE or ECONNRESET) as having no live sessions, so listing sessions (nmsh --list) no longer fails in that window. Replace fixed test delays with condition-based synchronization: wait for the fullscreen app to exit before typing after it, resend the mouse report until the reattached app answers, wait for the sleep to own the terminal before Ctrl+Z and to be running again before Ctrl+C, wait for the journal before killing a frontend, and dispose sandboxes only once no service accepts connections. Retire scripts/pty-history-smoke.mjs: it asserted retired UI text, ran against the real config and session service, and is covered by deterministic tests. Document recovery, updates, limits and known limitations.
Recovery could archive one detached session twice: a launch that lost the spool claim still archived the linked journal from an empty spool, and TranscriptStore.save does not serialize writers, so its journal-only archive could overwrite the complete one. Kill Session read the spool without claiming it and could race recovery the same way. A leftover spool whose journal was already ended was replayed over the finished transcript. Recovery and Kill Session now share finalizeLiveSession. It takes a cross-process lock on the journal (a dead owner's lock is taken over), claims the spool by rename, skips a journal that is already ended, and puts the spool back on failure. A launch that lost the claim no longer archives. Live journal checkpoints take the same lock, and claims abandoned by a crashed launch are restored. Reattaching to a fullscreen app suspended NMSh's own mouse and paste modes but never re-sent the app's, so a real terminal stopped reporting the mouse. The service now tracks the input modes the app set and the reattaching frontend re-applies them. Tests: deterministic concurrent-recovery, finalized-journal, crashed-claim, spool-less and lock tests; a host-mode assertion on mouse reattach; the fallback notice states the window cannot detach; job-control tests wait on process state instead of fixed delays, with an escaped pgrep pattern and sandbox cleanup on failure.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #131
What it does
nmshd.sockfor v1,nmshd-v<N>.sockafter that). An older service keeps its sessions running after an update. A newer frontend never archives, attaches to or ends sessions it cannot verify, and it says so at launch./resumeopens, sessions that ended with no window attached are archived with a factual note. If the shell exited while detached, the note has its exit code and the detached output is kept. If the service stopped or the system restarted, the note says so. A spool is claimed by rename before archiving, so it is never archived twice. On failure the spool is kept.NMSH_MAX_SESSIONS). A new window over the limit falls back to in-process with a notice. Detached sessions are never ended to make room./resumeshows how long each idle live session has been at its prompt.nmsh --listno longer errors in that window.Test stability work
Earlier failures in the full hardening file came from test synchronization, not product bugs. Each was reproduced first:
sleepprocess state (+foreground, notT).scripts/pty-history-smoke.mjsis retired. It asserted retired UI text, ran against the real config and live service, and is covered by deterministic tests.Verification
git diff --checkcleantests/suggestionRanking.test.ts, a wall-clock p95 budget) under heavy parallel loadlistLiveSessionstest fails without the fixKnown limitations / follow-ups (not in this PR)
nmsh-zdotdir-*behind. The pre-existing semantic helper also leavesnmsh-semantic-*directories. Both are pre-existing and tiny, and are left for a separate issue.