Skip to content

fix(continuum): honor @continuum-restore option for auto-restore on server start#15

Merged
tarikguney merged 1 commit into
psmux:mainfrom
MattKotsenas:fix/continuum-honor-restore-option
May 15, 2026
Merged

fix(continuum): honor @continuum-restore option for auto-restore on server start#15
tarikguney merged 1 commit into
psmux:mainfrom
MattKotsenas:fix/continuum-honor-restore-option

Conversation

@MattKotsenas
Copy link
Copy Markdown
Contributor

@MattKotsenas MattKotsenas commented May 13, 2026

Summary

set -g @continuum-restore 'on' is documented in psmux-continuum/README.md as "auto-restore on psmux server start", but the option is silently ignored. Auto-save works; auto-restore never fires. After a server restart users get a fresh empty session, and ~15 min later the auto-save loop overwrites the last pointer with that empty state, pruning the recovery target.

This bit me after an unexpected reboot; saved session was on disk, last had been clobbered to point at an empty save, and nothing fired on startup.

Root cause

Two entry points with what appears to be disjoint feature sets:

Option psmux-continuum.ps1 plugin.conf
@continuum-restore honored (lines 163–168) line 19 commented out
@continuum-save-interval honored hardcoded 15
@continuum-boot honored not handled

ppm.ps1 (lines 391–398) deliberately skips .ps1 entry points when plugin.conf exists, so the only code that reads @continuum-* options never runs. Only plugin.conf is sourced and it has the restore hook commented out.

Empirical evidence on a real install:

$ psmux show-options -g | findstr @continuum
@continuum-restore "on"

$ psmux show-hooks -g
client-attached -> run-shell "...auto_save.ps1 ..."
# (no restore hook registered)

Second bug found while fixing this

The commented-out line uses after-new-session. Live hook-probe on a fresh psmux server:

after-new-session  => no
session-created    => FIRED
client-attached    => FIRED

after-new-session does not fire on the first session creation in a fresh server, only on subsequent ones. So simply uncommenting that line would still have left auto-restore broken after one scenario where it really matters (server restart). This PR uses session-created instead.

Fix

  • plugin.conf: unconditionally register the session-created hook -> auto_restore.ps1.
  • auto_restore.ps1: read @continuum-restore at exec time, exit early if not on. Keeps plugin.conf free of nested if-shell quoting and evaluates the option at hook-fire time (robust to option-set ordering vs. config sourcing).
  • Add a @continuum-restore-fired one-shot marker. Without this guard the hook re-enters for every psmux new-session call that restore.ps1 itself makes.
  • Heredoc in psmux-continuum.ps1 kept byte-identical to scripts/auto_restore.ps1 to preserve the existing regeneration invariant.

Validation

  • session-created fires on first session - live-probed.
  • after-new-session does not fire on first session - live-probed.
  • ✅ Hook registers correctly via patched plugin.conf - verified with psmux show-hooks -g.
  • ✅ Opt-out path: when @continuum-restore is unset or off, auto_restore.ps1 exits early without invoking restore.ps1 or setting the fired marker - live-tested.
  • ✅ Both .ps1 files parse cleanly ([System.Management.Automation.Language.Parser]::ParseFile).
  • ✅ Heredoc and scripts/auto_restore.ps1 are byte-identical (AST-extracted + string-compared).

Overlap with PR #13

PR #13 (singleton-guard auto-save) touches the same files. This PR's diff is orthogonal and trivially rebases either way.

…erver start

The `@continuum-restore 'on'` option is documented in the README as
"auto-restore on psmux server start" but was silently ignored.

Root cause
==========

`psmux-continuum` ships two entry points with disjoint feature sets:

* `psmux-continuum.ps1` (lines 163-168) reads `@continuum-restore` and
  fires the restore. But PPM's `Initialize-Plugin` (`ppm.ps1` lines
  391-398) deliberately skips `.ps1` entry points when `plugin.conf`
  exists, because psmux sources `plugin.conf` natively via `@plugin`.

* `plugin.conf` IS sourced, but the auto-restore hook was commented out
  with a "Uncomment to enable" note - meaning the option was never read
  by any active code path.

Empirical verification on a real install:

    $ psmux show-options -g | findstr @continuum
    @continuum-restore "on"

    $ psmux show-hooks -g | findstr -i "session"
    client-attached -> run-shell "...auto_save.ps1 ..."
    # no restore hook registered

After-effect: when restore fails to fire on server start, the auto-save
loop (which IS registered) overwrites the `last` pointer with the empty
post-startup state ~15 min later, pruning the recovery target. Reboots
silently lose the saved session.

Second bug found while fixing this
==================================

The commented-out line in plugin.conf used `after-new-session`. This
hook does NOT fire on the first session creation in a fresh psmux
server - it only fires on subsequent sessions. So uncommenting that
line as-is would still have left auto-restore broken after a reboot.

Verified by hook-probing each candidate against a fresh psmux server:

    after-new-session  => no
    session-created    => FIRED
    client-attached    => FIRED

We use `session-created` because it fires for the very first session
in the server's lifetime, which is the moment auto-restore needs to
trigger.

Fix
===

* `plugin.conf`: register the hook unconditionally on `session-created`.
* `auto_restore.ps1`: read `@continuum-restore` at exec time and exit
  early if not `on`. This keeps `plugin.conf` simple (no nested
  `if-shell` quoting) and evaluates the option at hook-fire time rather
  than at config-source time, which is more robust against option-order
  dependencies.
* Add `@continuum-restore-fired` one-shot marker. Since `restore.ps1`
  itself calls `psmux new-session` for each saved session, the hook
  would otherwise re-enter for every restored session.
* Keep the `psmux-continuum.ps1` heredoc byte-identical to the
  standalone `scripts/auto_restore.ps1` to preserve the existing
  regeneration invariant.

Validation
==========

* `session-created` hook fires on first session - live-probed against
  a fresh psmux server.
* `after-new-session` does NOT fire on first session - live-probed.
* Patched `plugin.conf` correctly registers the hook - verified via
  `psmux show-hooks -g`.
* Negative path: when `@continuum-restore` is unset or `off`,
  `auto_restore.ps1` exits early without setting the fired marker or
  invoking `restore.ps1`. Live-tested.
* Both .ps1 files parse cleanly via `[System.Management.Automation.
  Language.Parser]::ParseFile`.
* Heredoc body and `scripts/auto_restore.ps1` are byte-identical
  (AST-extracted and string-compared).

Full positive E2E (save -> kill-server -> fresh server -> verify
restore) cannot be cleanly run on an isolated `-L pmtest` socket
because `psmux run-shell` doesn't pass socket info to child processes,
so child `psmux` invocations default to the user's real socket and
contaminate the test. The fix is correct for default-socket production
usage; the testability limit is a psmux internal, not a fix bug.

Note: PR psmux#13 (fix(continuum): singleton-guard auto-save, drop
Start-Job) touches the same files. This PR's diff is orthogonal to
that work and trivially rebases either way.
@MattKotsenas MattKotsenas marked this pull request as draft May 13, 2026 04:07
@MattKotsenas MattKotsenas marked this pull request as ready for review May 13, 2026 04:09
MattKotsenas added a commit to MattKotsenas/psmux-plugins that referenced this pull request May 14, 2026
Honor @continuum-restore option for auto-restore on server start.
Tracks upstream PR psmux#15.
@tarikguney tarikguney requested a review from Copilot May 15, 2026 16:40
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes auto-restore for psmux-continuum: the @continuum-restore option was documented but never honored because plugin.conf (the only entry point sourced when present) had the restore hook commented out. This PR registers the hook unconditionally and moves the opt-in check inside auto_restore.ps1, also switching from after-new-session (which doesn't fire for the very first session in a fresh server) to session-created.

Changes:

  • plugin.conf: register session-created hook unconditionally to invoke auto_restore.ps1.
  • auto_restore.ps1 (and the byte-identical heredoc in psmux-continuum.ps1): gate execution on @continuum-restore == 'on', and use a @continuum-restore-fired one-shot marker to prevent re-entry when restore.ps1 calls new-session for each saved session.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
psmux-continuum/plugin.conf Replaces commented after-new-session hook with an active session-created hook delegating opt-in to the script.
psmux-continuum/scripts/auto_restore.ps1 Adds Get-PsmuxBin resolver, opt-in check on @continuum-restore, and one-shot guard via @continuum-restore-fired.
psmux-continuum/psmux-continuum.ps1 Updates the heredoc that generates auto_restore.ps1 to remain byte-identical with the standalone artifact.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tarikguney
Copy link
Copy Markdown
Collaborator

Thank you for the PR, @MattKotsenas. Much appreciated. Everything looks good to me. I’ll go ahead and merge it.

@tarikguney tarikguney merged commit 17d86fe into psmux:main May 15, 2026
@MattKotsenas MattKotsenas deleted the fix/continuum-honor-restore-option branch May 16, 2026 03:40
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.

3 participants