Skip to content

feat(tui,adapters): warn when a reused tmux server would plant a stale state root (#731) - #5

Open
dracic wants to merge 3 commits into
mainfrom
feat/731-stale-state-root-warning
Open

dracic wants to merge 3 commits into
mainfrom
feat/731-stale-state-root-warning

Conversation

@dracic

@dracic dracic commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Review mirror of bmad-code-org#854 for Codex review. Not for merge here.

The interim for bmad-code-org#731: detect a reused tmux server that would plant a stale BMAD_LOOP_STATE_DIR in new panes, and say so. This is Stage 1 of the design in bmad-code-org#850. Carrying the root explicitly in the parked window's argv is Stage 2, a separate change.

Problem

A tmux server is long-lived, and its panes inherit the environment it was started with. A server cold-started under BMAD_LOOP_STATE_DIR=S1, then reused by a launch under S2, hands S1 to the parked engine window and every window-0 shell. The engine writes its control plane where the launcher never looks, and the live run reads as gone.

Change

  • TerminalMultiplexer.inherited_env(session, name, *, on_fault=None): a new non-abstract query for what a new pane will inherit. It answers None (unknown, the seam default), the UNSET sentinel (known absent), or the value, "" included. It never raises; a query that was attempted and failed reports through on_fault rather than folding into "unknown".
  • tmux: implemented on TmuxMultiplexer, not BaseTmuxBackend. It runs show-environment -t =S NAME, plus a -g fallback on an exact unknown variable miss. Reply shapes were measured on tmux 3.4: NAME=v, NAME=, the -NAME removal marker, misses, and a missing session.
  • psmux: keeps "unknown". Its show-environment shows only PSMUX* / TMUX* names, so it cannot see an inherited BMAD_LOOP_STATE_DIR; the per-project registry already closes the ordinary path there.
  • runs.resolve_state_root(env, passwd_home): the state-root cascade as a pure function. runs.state_root() delegates to it and is byte-identical: a differential over 2560 env combinations on both Windows and Linux found 0 mismatches. The passwd home is looked up lazily and only used when HOME is absent, because absent and empty HOME are different inputs.
  • _ensure_ctl_session: after both the create and the reuse arm, it compares the root a new pane would resolve with the launcher's own. On a mismatch it warns once per process through the TUI, naming both roots and giving a shell-quoted remedy.
    • Unknown answers are silent.
    • Query faults are reported.
    • An underivable launcher root is reported.
    • The launch is never blocked.
  • docs/multiplexer-backends.md: a new subsection with the operator remedy. CHANGELOG Fixed.

Compatibility

A StubMux that implements only the released abstract set completes both _ensure_ctl_session arms with no warning and no error. Out-of-tree backends need no change.

Tests

11 gates were ablated, each confirmed to fail its test without the gate. These include: the fault path, placing the implementation on the base class (psmux test), passwd use on an empty HOME, eager passwd lookup, a raw-override comparison instead of resolved roots, the loose unknown variable match, and the remedy quoting.

Local results

  • Windows, single files: 1516 passed. 4 failures in test_runs, all environmental symlink WinError 1314.
  • WSL, the 6 touched test files: 1586 passed, 0 failed.

Refs bmad-code-org#731 bmad-code-org#850

Summary by CodeRabbit

  • Bug Fixes
    • The TUI now warns once when new tmux windows may use a different state directory. The warning identifies both directories and suggests how to correct the tmux environment; launching continues.
  • Documentation
    • Added guidance for resolving state-directory differences in tmux, including how existing shells are affected.

dracic added 2 commits October 2, 2026 21:54
…e state root

A tmux server is long-lived, and its panes inherit the environment it
was started with. A server cold-started under BMAD_LOOP_STATE_DIR=S1,
then reused by a launch under S2, hands S1 to the parked engine window
and every window-0 shell. The engine then writes its control plane
where the launcher never looks, and the live run reads as gone (bmad-code-org#731).
This is the interim from the bmad-code-org#731 design: detect it and say so; carrying
the root explicitly is a later change.

- TerminalMultiplexer.inherited_env(session, name, *, on_fault=None) is
  a new non-abstract query answering what a new pane will inherit:
  None (unknown, the seam default), the UNSET sentinel (known absent),
  or the value ("" included). It never raises; a failed query reports
  through on_fault instead of folding into unknown.
- TmuxMultiplexer implements it with show-environment -t =S NAME, plus
  the -g fallback on an exact "unknown variable" miss. It sits on
  TmuxMultiplexer, not BaseTmuxBackend, so psmux keeps "unknown": its
  show-environment cannot see inherited values.
- runs.state_root is now runs.resolve_state_root(os.environ,
  passwd_home), byte-identical over 2560 env combinations on Windows
  and Linux. The passwd home is looked up lazily and used only when
  HOME is absent: absent and empty HOME are different inputs.
- _ensure_ctl_session compares the root a new pane would resolve with
  the launcher's own, after both the create and the reuse arm, and
  warns once per process through the TUI with a shell-quoted remedy.
  Unknown answers are silent, faults are reported, and the launch is
  never blocked.

Out-of-tree backends written against today's seam are unaffected: a
StubMux implementing only the released abstract set completes both
arms with no warning.

Known gaps:
- Windows test_runs has 4 environmental symlink WinError 1314 failures.
- WSL ran the 6 touched test files only (1586 passed). The rest of the
  Linux suite is unverified locally.
- trunk check could not run locally (a broken ruff plugin); ruff,
  prettier and pyright were run directly.

Refs bmad-code-org#731
@dracic

dracic commented Oct 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-05T06:52:48.000888Z 33f4993 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: eab9e5b0e7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…set-environment

On tmux, bmad-loop-ctl is one session shared by every bmad-loop project on that server, so the stale-state-root remedy re-roots new windows for all of them. The warning and the docs now say so, offer set-environment only where no other project uses another state root, and say that kill-server ends every session on the server, live runs included. Tests cover the shared-server wording and a set-empty inherited override, which stays silent; the cascade spec gains empty-override rows; two redundant force_tmux_backend marks are dropped.

Refs bmad-code-org#731
@dracic

dracic commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 33f499399c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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