Repository navigation
psmux 3.3.8 -> 3.3.9 adoption: umbrella for the floor bump, workaround retirement, and the follow-on tracks #660
Description
Umbrella for the psmux 3.3.8 adoption family, in the shape of #288 (which closed when its target-resolution children were done). The children below are separate work tracks with one shared premise: every upstream defect this backend works around is fixed and released — psmux 3.3.8 (66cf613 2026-08-18) is byte-identical to the v3.3.8 tag and to master, all 19 reports filed from this project are closed and released in it, and each workaround premise was re-measured against the installed binary (smoke tables and the F1–F9 proposal).
The one sequencing rule
_LAST_UNSUPPORTED → (3,3,7) (the F1 gate in #658) is the single constant everything hangs on: it refuses 3.3.7 and admits 3.3.8+, and 3.3.8 is the first tag carrying every fix at once — there is no per-workaround floor. Workaround deletions land only behind it (on a 3.3.7 install the pipe-pane -o transport, for one, silently kills run-log capture). F6/F7 in #658 are the exception: correct on both versions, landable any time.
Children
- psmux 3.3.8 adoption: bump the floor to (3,3,7) and drop the retired workarounds #658 — floor bump + workaround retirement (F1–F7): the
select_windowoverride group, the pipe-pane sidecar, the_transportablenarrowing, thekill_session=nameoverride,kill-windowfailure surfacing, and the doc-rot pass. Actionable now. Its merge closes psmux 3.3.8: adopt as installed floor, re-verify the switch-client/select-window paths, and drop the psmux#497 and other workarounds #222. - psmux 3.3.8: adopt as installed floor, re-verify the switch-client/select-window paths, and drop the psmux#497 and other workarounds #222 — the historical upstream-wait tracker; carries the evidence. Closes when psmux 3.3.8 adoption: bump the floor to (3,3,7) and drop the retired workarounds #658's set merges, per the closure proposal.
- psmux 3.3.8: attended console pass for the client-movement paths, then rebase switch_client's verdict source #659 — attended console pass for the five client-movement items, then the
switch_clientverdict-source rework (F8/F9). F8 done: all five items measured green against a real attached client (results) — the console premise is discharged, and the pass was scripted rather than hand-run, so it repeats. F9 implemented in fix(psmux): rebase switch_client's verdict on the exit code it can trust #670; the issue closes on that merge. The pass also produced psmux: current_window_id/current_pane_id answer for the server's active window, not the calling pane #669 and showed F9's premise was understated: the wrong verdict did not just answer False, it fired-land relocated the operator, then read the relocation as success. - psmux: adopt PSMUX_DATA_DIR as a per-project registry root — seam-wide, not a create-call env tweak #537 —
PSMUX_DATA_DIRas a per-project registry root, seam-wide. Unblocked by the same F1 gate (the installed build honours the variable, measured); stillneeds-designfor the root derivation and the cross-process contract.
Not children, but watched from here
- set-option parses flags after the option name: a dash-leading value is eaten —
-udeletes the key at rc 0, and there is no--end-of-options (3.3.8) psmux/psmux#583 — a-u-shaped option value still deletes the key at rc 0 on 3.3.8, so_transportable'svalue.startswith("-")clause stays after psmux 3.3.8 adoption: bump the floor to (3,3,7) and drop the retired workarounds #658's F4. When a tag ships that fix, its retirement is a small follow-up with its own tag gate. - psmux/psmux#580 question — if the new pane-scoped option store ever opens to user
@keys, retiring the@opt_@Nsubstitute channel becomes a follow-up with its own tag gate and live smoke. If the allowlist is declared deliberate, the psmux#321 boundary is double-confirmed and nothing changes.
Permanent boundaries — no child should try to retire these
Per-window user options do not exist in psmux's model (psmux#321); -EncodedCommand stays the window-command transport (quoted command strings still die on 3.3.8, root-caused in the psmux#402 comment); _qualified_window_id stays (a bare @N still routes by caller's server); the #{session_attached} delta probes stay for switch-client -l / detach-client, where rc proves dispatch, not effect.
Refs: #288, psmux/psmux#483, psmux/psmux#497, psmux/psmux#482, psmux/psmux#563, psmux/psmux#558, psmux/psmux#545, psmux/psmux#583
Related, deliberately outside the umbrella
Open issues that mention psmux but are bmad-loop-side work no psmux tag affects — defects, plus the coverage the family's own claims lean on. Listed so the boundary is a decision, not an omission:
- BaseTmuxBackend.list_window_ids folds every nonzero exit to [], so a failed listing reads as an empty session #525 / list_windows folds a transport fault to an empty listing, so a faulted ctl candidate scan reads as "nothing to prune" #562 — the seam folds non-zero exits and transport faults to empty listings. Same swallow family as psmux 3.3.8 adoption: bump the floor to (3,3,7) and drop the retired workarounds #658's F6, and 3.3.8 makes it worse to keep (more verbs now return meaningful non-zero), but the fix is seam honesty, not adoption. Whoever lands F6 should read both first.
- TUI: ctl_window_id admits an untagged control window on run-id collision, so two projects can attach to or kill each other's #531 / Untagged sessions still have no ownership proof that outlives the run dir (#419 direction 2, now unhomed) #538 — ctl-window collision and ownership proof outliving the run dir. Backend-agnostic design work; the per-project
-Lnamespace idea recorded on psmux 3.3.8: adopt as installed floor, re-verify the switch-client/select-window paths, and drop the psmux#497 and other workarounds #222 (opportunity 2) is one candidate shape for Untagged sessions still have no ownership proof that outlives the run dir (#419 direction 2, now unhomed) #538. - psmux: current_window_id/current_pane_id answer for the server's active window, not the calling pane #669 —
_display_messageprobes without-t $env:TMUX_PANE, socurrent_window_id/current_pane_id/current_return_targetanswer for the server's active window rather than the calling pane. Surfaced and measured by psmux 3.3.8: attended console pass for the client-movement paths, then rebase switch_client's verdict source #659's attended pass, but no psmux tag moves it: the fix is the leaf pinning its own probe, exactly as_parked_traileralready does. Blast radius is the ctl-window prune's self-exclusion and the return-option read, not the adoption. - psmux: the client-verb probes aim their -t at an unguarded session name, and read the attached count with a substitutable target #671 — the same leaf's other probe-targeting residuals, both pre-dating the adoption: an unguarded
:-bearing session name goes straight intodisplay-message -t <session>(the Parked-window return target is a bare pane id — unresolvable cross-session on psmux (one server per session) #221 rule the sibling call sites already apply), and the attached-client count is read with a target a foreign server can answer (fix(adapters): give psmux a per-window option channel #315). The second one is why it is listed here rather than parked: psmux 3.3.8: attended console pass for the client-movement paths, then rebase switch_client's verdict source #659's F9 made that count load-bearing in the NONZERO direction, where a borrowed count would vouch for a switch that moved nobody. - adapter seam: document the qualified-id obligation once, not per backend #311 — document the qualified-id obligation once at the seam. Adjacent to psmux 3.3.8 adoption: bump the floor to (3,3,7) and drop the retired workarounds #658's F7 doc pass but homed in the adapter guide, not
psmux_backend.py. - ci: install psmux on Windows runner to enable live multiplexer gates in CI #662 (PR ci(windows): run the psmux live gate in CI instead of before releases #668) — install psmux on the Windows CI runner. Not a defect, and the reason it sits here rather than in the children: every
test_premise_*andtest_adopted_*probe this family added lives intests/test_psmux_live.py, which no CI job runs today — the Linux matrix skips it onsys.platform, and the Windows runner has no psmux on PATH. The adoption's entire evidence base is therefore observed only by hand on a developer box, and psmux 3.3.8: attended console pass for the client-movement paths, then rebase switch_client's verdict source #659's F9 raised the stakes by putting two upstream exit-code premises under the same skipped module. Until this lands, a psmux behaviour drift is a silent green.
Activity
coderabbitai commentedon Aug 19, 2026
🔗 Related PRs
#427 - fix(adapters): guarantee a single-line multiplexer version() (
#321) [merged]#517 - test(adapters): probe psmux workaround premises, not just our reaction [merged]
#523 - fix(runs,tui): tag project ownership with a transportable digest [merged]
#661 - psmux 3.3.8: bump the floor and retire the workarounds it makes dead [merged]
#670 - fix(psmux): rebase switch_client's verdict on the exit code it can trust [open]
#668 - ci(windows): run the psmux live gate in CI instead of before releases [open]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
You can configure auto-planning by selecting labels in the issue_enrichment configuration.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
pbean commentedon Aug 21, 2026
Status pass from the 2026-08-20 tracker overhaul — three of the four children are now closed, and two of the umbrella's own caveats are discharged.
Children: #658 ✅, #222 ✅, #659 ✅ (F9 shipped in PR #670). #537 is the only one left open.
Two things this umbrella flagged as outstanding have since landed, so the text around them is now stale in your favour:
.github/workflows/ci.ymlnow resolves the latest psmuxwindows-x64release asset, installs it on the Windows runner, and runs the live gate in its own serial step. The adoption's evidence base is no longer observed only by hand on a developer box, which was the stated reason that item sat here rather than in the children.[ ] #659reasoning is discharged by PR fix(psmux): rebase switch_client's verdict on the exit code it can trust #670 and PR fix(psmux): pin display-message self-probes to the calling pane #672. psmux: current_window_id/current_pane_id answer for the server's active window, not the calling pane #669 also closed with fix(psmux): pin display-message self-probes to the calling pane #672, so the one piece of rot you called out in the "deliberately outside the umbrella" map is gone.This issue stays open. I proposed closing it during triage on the #288 precedent — three of four children done — and the adversarial pass refuted that, correctly. The umbrella carries content that lives nowhere else: the "Permanent boundaries — no child should try to retire these" section, and the watch entries for psmux/psmux#583 and psmux/psmux#580. Closing would strand both. The close becomes right the moment #537 lands, or #537 is explicitly re-parked on-thread as pure design-wait.
One suggestion before that day comes: give psmux/psmux#583's retirement trigger a home — either a
test_premise_*probe beside the #580 one intests/test_psmux_live.py, or a line on #537's thread. Right now the trigger for retiring_transportable'svalue.startswith("-")clause exists only in this issue's prose, and that is precisely the content a close would lose.Labels: added
P4(the issue carried no priority). Deliberately not addingblocked:upstreamorneeds-design— the remaining action here is a status comment, not code, and #537 carries the design question itself.feat(adapters,runs): give psmux a per-project registry root
feat(adapters,runs): give psmux a per-project registry root
dracic commentedon Aug 26, 2026
#537 and #728 — done.
New entry for "Not children, but watched from here"
the single-server name mutex ignores PSMUX_DATA_DIR, so two registries cannot both hold a session of the same name — including __warm__ (3.3.8/master) psmux/psmux#599 — psmux keys its single-server mutex on the session name, not on
PSMUX_DATA_DIR:acquire_session_mutexbuildsLocal\psmux-session-{port_file_base}(platform.rs:346) andport_file_base()never sees the data root (types.rs). Two correctly-isolated registries therefore still share one global name namespace, so a fixed control-session name fails every project's launch but the first. psmux: adopt PSMUX_DATA_DIR as a per-project registry root — seam-wide, not a create-call env tweak #537 works around it by suffixing the control session with the registry digest. Reproduced twice on installed3.3.8 (66cf613), byte-identical betweenv3.3.8and master60e59fb.Its retirement is retire the per-registry control-session name once a psmux release carries the psmux#599 fix #733, and it is version-gated in the shape psmux 3.3.8 adoption: bump the floor to (3,3,7) and drop the retired workarounds #658 used — the suffix goes only behind a
_LAST_UNSUPPORTEDbump to a release carrying the fix, because deleting it while an unfixed build is supported reinstates the failure. Unlike most of this family the retirement is operator-visible: the session name changes back.Also measured on 3.3.8 and worth knowing here: the
__warm__replacement server collides the same way, so the second registry on a machine never publishes a warm server at all — no user-chosen name involved.Follow-ups opened from #537, not children of this umbrella
Each is a question the branch measured and then declined to guess at, rather than an unfinished task:
PSMUX_DATA_DIRshould mean #729 — what an operator's own ambientPSMUX_DATA_DIRshould mean. Two operators produce byte-identical environments needing opposite answers; four inherited-token designs each closed one horn and opened the other.PSMUX_BARE_ENV#730 — whether to supportPSMUX_BARE_ENV=1. Needs an env transport on the session and parked-window verbs; five review rounds showed a compatibility shim cannot be made safe, so it likely needs an explicit seam-contract revision.BMAD_LOOP_STATE_DIRinto every window it spawns #731 — a stale multiplexer server substituting its ownBMAD_LOOP_STATE_DIR. Measured identically onmain, so it predates psmux: adopt PSMUX_DATA_DIR as a per-project registry root — seam-wide, not a create-call env tweak #537; should be designed with psmux: decide whether bmad-loop should supportPSMUX_BARE_ENV#730.Update 2026-08-31 — two later issues, and a labelling gap that hides most of this list
Two more in the family, opened after the comment above
-n, so it is the only window bmad-loop does not name #738 —new_sessionis the only window-creating call that omits-n, so a session's initial window is the one window bmad-loop never names. Split out of Two concurrent unattended runs preceded a machine hang (Kernel-Power 41, no bugcheck) — original autorename diagnosis retracted, see correction #673 after that issue'sautomatic-renamediagnosis was retracted by its reporter; the hang half stays on Two concurrent unattended runs preceded a machine hang (Kernel-Power 41, no bugcheck) — original autorename diagnosis retracted, see correction #673. Leaf-local, four isolated sites,good first issue.Status refresh
list_window_idsnow answers[]only when stderr proves the session gone (_SESSION_GONE_STDERR, measured on tmux 3.4 and psmux 3.3.866cf613) and raisesMultiplexerErrorotherwise; every_window_alivecaller already treated that as "unknown, not dead", so no engine change was needed.list_windowsandsession_optionskeep their sentinel but now warn when the failure proved nothing — so list_windows folds a transport fault to an empty listing, so a faulted ctl candidate scan reads as "nothing to prune" #562 and Untagged sessions still have no ownership proof that outlives the run dir (#419 direction 2, now unhomed) #538 are narrowed, not closed.live_session_may_be_ours— "a listing that cannot answer reads as 'no session'" — is the same conflation, one layer up. The seam can now tell the two apart, so the removal guard's degrade is a choice again rather than a limitation. Whoever picks up delete/archive/clean can remove a live run's directory when the multiplexer cannot be observed — revisit the guard's documented degrade #732 should read PR fix(adapters): tell a failed window listing apart from an empty session (#525) #751 first.The labelling gap
#729, #730, #731, #732, #733 and #750 carry no labels at all. A search by
area:psmuxreturns four open issues and misses every one of them, which makes this family look nearly finished when it is not. They should be labelled before the next sweep, or the next person planning work here will draw the same wrong conclusion.Update — #732 closed by measurement, and it produced an upstream report plus its own retirement
has-sessionwhose 500 ms connect does not land reaps a live session's registry entry, andlsthen exits 0 without that session and with nothing on stderr until the server's registry maintenance re-writes it — a nominal 5 s check, so the window has no hard bound. Retry-with-delay, a tag-first read, and a proof discipline were each weighed and refused, with reasons recorded at the guard.has-sessionis the one reap site in the binary that does not gate onConnectionRefused, while its four siblings do and say so in their own shared comment; it also skips the PID anchor they consult. tmux 3.4 blocks rather than reaping under the same treatment and never mutates registry state from a read-only predicate. Precedent: psmux#546 accepted and fixed the same defect atcleanup_stale_port_files— this is the site that fix did not reach.80362faand are unchanged sincev3.3.8— 42 commits touch those paths, none of them these.has-sessionreap 2552→2842, load false-negative 855→906, registry tick 1277→1330.feat(adapters,runs): give psmux a per-project registry root
feat(adapters,runs): give psmux a per-project registry root
[-]psmux 3.3.8 adoption: umbrella for the floor bump, workaround retirement, and the follow-on tracks[/-][+]psmux 3.3.8 -> 3.3.9 adoption: umbrella for the floor bump, workaround retirement, and the follow-on tracks[/+]dracic commentedon Oct 2, 2026
Status 2026-10-02: the upstream half is fixed on psmux master, and nothing is released yet
All three upstream defects this family's remaining retirements wait on are fixed on psmux
master. None of them is in a release: the latest tag is stillv3.3.8, master ise36bd85(694 commits past it), andCargo.tomlstill reads3.3.8.PSMUX_DATA_DIR)29bff00set-optionvalue eaten, no--)524babc_transportable'svalue.startswith("-")clause (no issue of its own yet; see below)has-sessionreaps a live.porton a connect timeout)9f141d1(mergea755158)The sequencing rule is unchanged: one
_LAST_UNSUPPORTEDbump to the first release whose tag contains all three commits, verified withgit tag --contains, and every retirement behind it. Deleting any of them on 3.3.8 reinstates the defect.Watch-list entry psmux/psmux#580: no change, now source-confirmed. psmux/psmux#648 (closed, on master) gave every window its own option table and routes
-wwrites to it, which looked like it might open per-window user options. It does not:is_window_scoped_writedeliberately excludes@names, because every psmux read of an@name still goes through the session-wideuser_optionsmap (src/server/options.rs, the doc comment aboveis_window_option's caller). The permanent boundary in this issue stands, and the@opt_@Nsubstitute channel stays.A new master change that the next release will carry, unmeasured against us so far:
303c9a3(merged in41a02fc) puts every pane process into aKILL_ON_JOB_CLOSEjob object that the server holds. When a psmux server ends, its panes' whole process trees now end with it, where on 3.3.8 they could outlive it. A server started from inside a pane breaks away, and so does aStart-Processchild. Before adoption, the live gate gets run against a master build to check parked engine windows, per-registry servers spawned from panes, andkill-window/kill-sessionreaping of agent trees.On the retirement trigger pbean asked to give a home: the plan is
test_premise_*probes intests/test_psmux_live.pyfor psmux#583 and psmux#599, plus psmux#622 if it can be forced deterministically. Each probe asserts today's 3.3.8 defect and is shown red against a master build before it lands. The Windows CI job installs the latest psmux release, so these go red on their own the day a release carries the fixes, and the trigger stops depending on someone rereading this issue.Remaining bmad-loop-side work in the family, all independent of the release: #729 (implementation of the
[mux]boolean the issue proposes), #750 (measure window-id reuse first, then a pane-pid identity proof), #730 + #731 (an ADR for the env transport across the session and parked-window verbs first, then the #731 interim warning, then the seam revision).test(psmux): tripwire probes for three upstream fixes awaiting release
dracic commentedon Oct 8, 2026
Status, 2026-10-08.
Merged:
PSMUX_BARE_ENV#730, a stale multiplexer server substitutes its ownBMAD_LOOP_STATE_DIRinto every window it spawns #731).[mux] honor_ambient_psmux_data_dir(closes psmux registry: decide what an operator's ownPSMUX_DATA_DIRshould mean #729). It also clears a resumed run's stale session in a displaced registry, and requires an ownership proof for by-name session operations in a shared registry.-udeletes the key at rc 0, and there is no--end-of-options (3.3.8) psmux/psmux#583, fix: record an auto-sweep trigger only once its child has started (#501) #599 and fix(engine): stop refusing an isolated merge over unrelated untracked files (#460) #622. Each probe asserts today's 3.3.8 defect, so the Windows CI psmux job, which installs the latest release, goes red on its own the day a release carries the fixes. That is now the retirement trigger for retire the per-registry control-session name once a psmux release carries the psmux#599 fix #733, narrow the removal guard's documented ceiling once a psmux release carries the psmux#622 fix #754 and_transportable's dash-leading clause.BMAD_LOOP_STATE_DIRinto every window it spawns #731 interim warning, with the shared-control-session remedy.Open:
Standardmode for batch launchers. This is ADR 0001's argv-fidelity precondition for Stage 2.cleanup, read an unavailable backend as "nothing to prune". The evidence-gated fix is in progress.pwshexecutable. This is a low-risk follow-up to fix(psmux): refuse PowerShell older than 7.3 before launching a window (#861) #862.Next: ADR Stage 2,
--state-rootand--registry-rootin the parked-window argv, after #862. It closes #731 and re-scopes #730.Still blocked upstream: #733 and #754 wait for a psmux release after
v3.3.8, which is still the latest; the tripwires from #852 will flag it.Watch list:
@user options, so the per-window user-option boundary here stands.303c9a3). The live gate showed no drift against a master build, and it is worth a re-run on the release.#673 is still waiting on the reporter's retest.
dracic commentedon Oct 9, 2026
Status, 2026-10-09.
Merged: #862 (pwsh 7.3 floor), #869 (closes #864: cleanup reports a scan error instead of "clean" when the backend is unavailable and there is evidence of a live run), #870 (closes #731: ADR 0001 Stage 2, state and registry roots in the parked argv; also fixes a tmux park that exited under dash), #871 (closes #863: probe and launch the same absolute pwsh path). #730 is closed as completed against ADR 0001 answer B.
In progress: #868, the run pid reader blocking on a FIFO
engine.pid.Waiting on the next psmux release: #733 (psmux/psmux#599), #754 (psmux/psmux#622) and
_transportable's dash-leading clause (psmux/psmux#583). The #852 tripwire probes turn the Windows psmux CI job red when a release carries the fixes; that is the trigger for all three.dracic commentedon Oct 10, 2026
Status, 2026-10-10: smoke bug-hunt against psmux 3.3.8 and master
10640ec8We ran an adversarial smoke hunt over bmad-loop's psmux surface on both the 3.3.8 release (
66cf613) and current master (10640ec8, what 3.3.9 will be cut from), with tmux 3.4 as the parity reference. Every finding was reproduced from PowerShell (the supported launcher on native Windows) and independently confirmed twice before filing.Filed upstream (3.3.8 and master):
PATH/TEMP, so a parked window can run a differentpsmuxthan the one that started the server.=, sokill-session -t =NAMEkills a differently-cased session (3.3.8, master) psmux/psmux#774: session names match case-insensitively, even with=, sokill-session -t =NAMEkills a differently-cased session. Our lower-case folding of run ids is what keeps us safe today.show-environmentignores NAME, omits inherited variables and prints removals as empty values. Our inherited-environment query therefore cannot answer on psmux, so the stale state-root warning never fires on Windows.Filed here, both in progress:
resolvein progress #876:cleanupcloses a control window whose command is still running (for example an interactiveresolve) when the run's engine pid is dead.psmuxby bare name, so under pane environment: registry values replace the server's inherited PATH and TEMP, so panes lose the launching shell's PATH (3.3.8, master) psmux/psmux#773 it can resolve a different binary, or none, inside the pane and silently fail to return the client. The fix pins psmux's absolute path in the trailer; it is needed on 3.3.8 too. PR fix(psmux): pin psmux's absolute path in the parked-window trailer #878.Retirement: #879 tracks removing the #877 pin and our case-folding session key once a psmux release carries the psmux/psmux#773 and psmux/psmux#774 fixes, behind the same
_LAST_UNSUPPORTEDsequencing as #733 and #754.For the 3.3.9 adoption: with master
10640ec8on PATH, the live gate turns red on exactly the threetest_premise_*tripwires (psmux/psmux#583, psmux/psmux#599, psmux/psmux#622), as designed, and the bmad-loop session lifecycle, client movement and return paths behave the same as on 3.3.8. The tripwires remain the retirement trigger for #733, #754 and_transportable's dash-leading clause.Status, 2026-10-10: psmux fixed all three hunt issues on master.
The maintainer fixed psmux/psmux#773 (merge 691e39a2), psmux/psmux#774 (51c58756) and psmux/psmux#775 (62026a80 + 69e355fb). We retested each repro unchanged on master
3b1c3ac6, 3 of 3 runs. No release tag contains any of these merges yet.PATH/TEMP(new-session, new-window, claimed warm session), and the in-panepsmuxis the build that started the server. retire the trailer's pinned psmux path once psmux releases the psmux#773 fix; the case-folding session key stays #879 item 1 (the psmux: the parked-window trailer runs psmux by bare name, so it can resolve a different binary or none in the pane #877 trailer pin) retires behind the_LAST_UNSUPPORTEDbump to the first release containing 691e39a2. fix(psmux): pin psmux's absolute path in the parked-window trailer #878 is still needed on 3.3.8 and needs no change.=, sokill-session -t =NAMEkills a differently-cased session (3.3.8, master) psmux/psmux#774 fixed, with a design limit:=nametargets are exact andrename-sessiononto a live name is refused. Two sessions whose names differ only in case can't coexist; a case-only duplicatenew-sessionis refused withduplicate session:. So our lower-case session key stays permanently and is no longer a retirement item (retire the trailer's pinned psmux path once psmux releases the psmux#773 fix; the case-folding session key stays #879 updated). bmad-loop creates every session name in lower case and never asks for a duplicate. Against a case variant held by someone else, master makes our launch fail loudly with theduplicate sessionrefusal instead of reusing that session.unknown variable,-NAMEremovals and a real-gscope now match tmux, and our tmuxshow-environmentparser accepts the replies. That makes a new follow-on possible once a release carries 62026a80: implementinherited_envfor psmux so the stale state-root note can fire on Windows. Two psmux specifics, both measured:-gmust be session-targeted (-g -t =<session> NAME), because psmux runs one server per session and an untargeted-ganswers from one fixed session's server. And the reply echoes the stored name spelling (-g PATHgivesPath=...), so the name must be matched case-insensitively.Live gate:
tests/test_psmux_live.pyon master3b1c3ac6gives 21 passed, with exactly the three expected tripwires red (psmux/psmux#583, psmux/psmux#599, psmux/psmux#622). On 3.3.8 it gives 24 passed. Nothing in the gate depends on the psmux/psmux#775 output changes: bmad-loop's psmux path never runsset-environment,show-environmentorupdate-environment.New tripwires to add (listed in #879): a
test_premise_*for psmux/psmux#773 (panePATHrebuilt from the registry) and for psmux/psmux#775 (named query ignored), and an ordinary-directiontest_adopted_*asserting that a case-only duplicate is refused.#880 and #881 are unaffected.
Status, 2026-10-13: psmux 3.4.0 is released. Floor bump and retirements in progress.
psmux 3.4.0 (
20aa1d7) is the first release after 3.3.8. There is no 3.3.9 tag. The tag carries every upstream fix this family waits on: psmux/psmux#583, psmux/psmux#599, psmux/psmux#622, psmux/psmux#773 (691e39a2), psmux/psmux#774 (51c58756) and psmux/psmux#775 (62026a80, 69e355fb).Live gate on installed 3.4.0, run from PowerShell: 23 passed. The five
test_premise_*tripwires are red, as designed:-udeletes the key at rc 0, and there is no--end-of-options (3.3.8) psmux/psmux#583, a dash-leading option value;has-sessionreap;PATH;show-environment.The ordinary-direction row #886 added for the case-only duplicate session passes.
Update, later on 2026-10-13: both PRs are open.
ci: pin the blocking psmux gate to one release and add a latest-release canary #899 pins the blocking psmux gate to one release (
v3.3.8), instead ofreleases/latest. 3.4.0's release had turned every PR red, because the premise tripwires fire by design. A new, non-required weekly canary runs the same gate against the latest release.feat(psmux): adopt psmux 3.4.0 and retire its five workarounds #900 (stacked on ci: pin the blocking psmux gate to one release and add a latest-release canary #899) adopts 3.4.0 in one atomic step:
_LAST_UNSUPPORTED → (3,3,8)), and the gate pin moves tov3.4.0;_transportable's dash-leading clause retires (set-option parses flags after the option name: a dash-leading value is eaten —-udeletes the key at rc 0, and there is no--end-of-options (3.3.8) psmux/psmux#583);inherited_envis implemented on psmux (show-environment ignores NAME, omits inherited variables and prints removals as empty values (3.3.8, master) psmux/psmux#775);test_adopted_*rows.The trailer's pinned psmux path (retire the trailer's pinned psmux path once psmux releases the psmux#773 fix; the case-folding session key stays #879 item 1) stays, by measurement: a pane inherits the PATH of whoever started the server, so a long-lived control session can still meet a server whose PATH lacks psmux. Live gate on 3.4.0, run from PowerShell: 28 passed.