Skip to content

psmux can destroy a live session out from under a run (psmux#546) — decide the exposure and whether the reconcile can tell #489

Description

@dracic

Summary

psmux/psmux#546 (filed from the pre-3.3.8 hunt, present on 3.3.7 and on master): the pre-boot
mtime guard in cleanup_stale_port_files() deletes a live session's whole registry set and
continues above the authoritative PID-anchor check (session.rs:1199-1212), after which the
orphan reaper terminates the still-running server. It runs on every psmux invocation, before
argument parsing — psmux -V is enough. Trigger is a forward wall-clock step with uptime unchanged
(VM save/restore, NTP step after booting with a slow RTC, mtime-preserving restore), not idleness.

So on Windows an orchestrated session can be destroyed mid-run by an unrelated psmux call, and the
destroying invocation exits 0 with nothing on stderr.

What this repo needs to decide

The upstream fix is a one-line reorder and will presumably land, but it is not in 3.3.8 as of
6ebc629, and the exposure exists on every release we admit today. Two questions, neither answered
anywhere in the codebase:

  1. Can a run tell? Session completion is hook-Stop-or-window-death by design. An externally
    reaped session presents as window death, so the engine would complete the session and hand it to
    the deterministic post-session verify — which finds no work done and escalates. That is a safe
    degradation but a misleading diagnosis: the operator is told the session finished and produced
    nothing. Worth deciding whether the reconcile can distinguish "the mux destroyed it" from "the CLI
    exited", e.g. by noticing the session vanished rather than just the window.
  2. What happens to the shared ctl session? tui/launch.py assumes the ctl session outlives every
    run (parked windows never self-close, pruning is manual). A reap takes the ctl session and every
    parked window's option keys with it, so the project tag map disappears and the untagged-session
    fallback behind Untagged sessions are weak ownership: they leak once their run dir is gone, and can be pruned by the wrong project on a run-id collision (the fallback behind #320) #419 becomes the only ownership signal.

Also worth re-verifying on the 3.3.8 admission

The delta reworks this whole area — d7d5b50 (#510 reaper scope), fef2217/6d8bc4b (#530 orphan
prune), e66b80d/cb098c0 (bounded sweep), 8cf3b1f (single warm server per namespace). Measured
baseline on a dev machine: 38 stale .sid files dated over three weeks, while a clean kill-session
leaves zero net files — i.e. the residue comes from sessions ending without kill-session
(window-death and crash paths), which is exactly the path #530's fix must be checked against.

Cheap mitigation available regardless: PSMUX_DATA_DIR (upstream 5152a2c, in 3.3.8) can point a
run's registry at a per-project root, which also bounds the blast radius of any cross-project reap.

Surfaced by the pre-3.3.8 bughunt

Refs: psmux/psmux#546, #222, #419

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions