Skip to content

fix(tmux-terminal): D5 probe + D6 node prefix (real-tmux execution)#100

Merged
lantiscooperdev merged 1 commit into
mainfrom
fix/p5-d5-d6-real-tmux
Jun 27, 2026
Merged

fix(tmux-terminal): D5 probe + D6 node prefix (real-tmux execution)#100
lantiscooperdev merged 1 commit into
mainfrom
fix/p5-d5-d6-real-tmux

Conversation

@lantisprime

Copy link
Copy Markdown
Owner

Summary

Fixes two bugs surfaced by exercising the implementation against a real tmux server (tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs). Both bugs were invisible to the v5 unit test suite because FakeTmuxExecutor returns configurable responses that don't model defaultTmuxExecutor's actual behavior or tmux's worker-execution semantics.

The bugs

D5 — isAvailable probe (tmux-backend.ts:34)

Before: ["has-session", "-t", "__pi_probe__"]

  • __pi_probe__ session doesn't exist by default → has-session returns exit 1
  • defaultTmuxExecutor catches non-zero exits and returns {ok: false}
  • The D1 result.ok === true check then made isAvailable always return false, even when the tmux server was reachable

Fix: probe with ["list-sessions"] — returns 0 when the server is reachable, regardless of session count. Correctly distinguishes server-reachable from server-unreachable.

D6 — launch argv missing node prefix (tmux-backend.ts:52)

Before: ["new-window", ..., "--", workerPath, manifestPath]

  • tmux tries to exec workerPath directly, but bg-worker.ts has no shebang and is mode 644 (not executable)
  • Window is created, then immediately destroyed because the command fails to exec
  • @pi_run_id and @pi_agent_name user-options are never set
  • isAlive returns false, list returns empty

Fix: prepend "node"["new-window", ..., "--", "node", workerPath, manifestPath]. node handles the .ts extension via --experimental-strip-types (the same mechanism used by run-p4-4-tests.sh and the other test runners in this repo).

Why these bugs survived the v5 review process

  • Plan review (5 rounds): focused on argv construction (Group 3 tests), not on isAvailable probe semantics or worker-execution semantics
  • Code review (1 round): verified argv shape against fake-recorded calls, did not exercise real tmux
  • Unit tests: FakeTmuxExecutor returns configurable responses; defaultTmuxExecutor's actual return shape (always {ok: false} for non-zero exit, no throw) was hidden behind the fake
  • "Manual smoke" done criterion (from v5 plan): "pi -e ./agents/index.ts -e ./tmux-terminal/index.ts then /agents bg scout 'echo hello' launches tmux window" — listed but never executed before merge

The new test-real-tmux-smoke.mjs makes this criterion mechanically verified in CI.

New: real-tmux smoke test

tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs (222 lines) + run-real-tmux-smoke.sh (7 lines):

  • Exercises the actual createTmuxBackend against an isolated tmux -L p5-smoke-<pid> socket (does NOT touch the user's default tmux session)
  • Cleans up on exit (kill-server + temp dirs)
  • 11 verification steps: backend.name, isAvailable probes real tmux, launch creates window, window visible via direct CLI, user-options set, isAlive, list recovers runId/agentName, kill removes window, isAlive after kill, kill idempotent
  • Skipped (exit 0) if tmux not on $PATH — opt-in by environment

Test updates

3 assertions in test-tmux-backend.mjs updated to match new contracts:

  • Group 2 test 1 (line 43): ["has-session", "-t", "__pi_probe__"]["list-sessions"]
  • Group 3 test 1 (line 99): deepEqual argv now includes "node" before workerPath
  • Group 4 test 1 (line 155): workerIdx + 1workerIdx + 2 for manifestPath position; added intermediate "node" check

Verification (all green)

Command Result
bash tmux-terminal/test-fixtures/run-p5-tests.sh 63/63 pass + REQ-13 OK
bash agents/test-fixtures/run-p4-4-tests.sh green (regression intact)
node tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs 11/11 pass against real tmux 3.6a
Mutation #1 (realpathSync → path.resolve) only testWorkerPathIsRealpathed fails ✓
Mutation #2 (WORKER_BASENAMES reorder) only testWorkerPathPrefersTsOverMjs fails ✓

Files changed (5 files, +246/-7)

  • tmux-terminal/lib/tmux-backend.ts — D5 probe + D6 node prefix
  • tmux-terminal/test-fixtures/test-tmux-backend.mjs — 3 assertion updates
  • tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs — NEW (222 lines)
  • tmux-terminal/test-fixtures/run-real-tmux-smoke.sh — NEW (7 lines)
  • agents/P3_IMPLEMENTATION_SLICES.md — D5/D6 + smoke test docs

Plan v6 note

D5 and D6 should be incorporated into v6 of the P5 plan as canonical recipe (probe = list-sessions, argv = [..., "--", "node", workerPath, manifestPath]). This PR ships them as post-merge fixes against v5.

🤖 Generated with pi-coding-agent

Two bugs surfaced by exercising the implementation against a real tmux
server (test-real-tmux-smoke.mjs). Both invisible to FakeTmuxExecutor
unit tests because the fake returns configurable responses that don't
model the real defaultTmuxExecutor / tmux behavior.

D5 — isAvailable probe (tmux-backend.ts:34)
- Before: `has-session -t __pi_probe__`. The __pi_probe__ session does
  not exist by default, so has-session returns exit 1.
- defaultTmuxExecutor catches non-zero exits and returns {ok: false}.
- The D1 result.ok === true check then made isAvailable always return
  false, even when the tmux server was reachable.
- Fix: probe with `list-sessions` — returns 0 when the server is
  reachable, regardless of session count. Correctly distinguishes
  server-reachable from server-unreachable.
- Test: test-tmux-backend.mjs Group 2 test 1 args assertion updated to
  ["list-sessions"].

D6 — launch argv (tmux-backend.ts:52)
- Before: `["new-window", ..., "--", workerPath, manifestPath]`. tmux
  tried to exec workerPath directly, but bg-worker.ts has no shebang
  and is mode 644 — not executable. The window was created then
  immediately destroyed (the command failed to exec); @pi_run_id and
  @pi_agent_name user-options were never set; isAlive returned false.
- Fix: prepend "node" to argv — `["new-window", ..., "--", "node",
  workerPath, manifestPath]`. node handles the .ts extension via
  --experimental-strip-types (used elsewhere in this repo).
- Tests: test-tmux-backend.mjs Group 3 test 1 deepEqual updated to
  expect "node" prefix; Group 4 test 1 workerIdx indexing updated to
  workerIdx + 2 for manifestPath (intermediate "node" check added).

New: tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs +
      run-real-tmux-smoke.sh
- Exercises the actual createTmuxBackend against an isolated
  `tmux -L p5-smoke-<pid>` socket. Does NOT touch the user's default
  tmux session. Cleans up on exit (kill-server + temp dirs).
- 11 verification steps: backend.name, isAvailable probes real tmux,
  launch creates window, window visible via direct CLI, user-options
  set, isAlive, list recovers runId/agentName, kill removes window,
  isAlive after kill, kill idempotent.
- Skipped (exit 0) if tmux not on $PATH — opt-in by environment.

Docs:
- agents/P3_IMPLEMENTATION_SLICES.md updated with D5/D6 rationale and
  the new real-tmux smoke test entry. Plan v6 should incorporate both
  fixes into the canonical recipe (probe + node prefix).

Why these bugs survived the v5 review (5 rounds) + code review (1 round):
- Plan review focused on argv construction (Group 3 tests), not on
  isAvailable probe semantics or worker-execution semantics.
- Code review verified argv shape against fake-recorded calls but
  did not exercise real tmux.
- Unit tests use FakeTmuxExecutor which returns configurable
  responses; defaultTmuxExecutor's actual return shape (always
  {ok: false} for non-zero exit, no throw) was hidden behind the fake.
- The "Manual smoke: pi -e ./agents/index.ts -e ./tmux-terminal/index.ts
  then /agents bg scout" criterion was listed but never executed before
  merge. The new smoke test makes this criterion mechanically verified.

Verification:
- bash tmux-terminal/test-fixtures/run-p5-tests.sh: 63/63 pass + REQ-13 OK
- bash agents/test-fixtures/run-p4-4-tests.sh: green (regression intact)
- node tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs: 11/11 pass
- Mutation #1 (realpathSync → path.resolve): only testWorkerPathIsRealpathed fails
- Mutation #2 (WORKER_BASENAMES reorder): only testWorkerPathPrefersTsOverMjs fails
- Both mutations revert cleanly
@lantiscooperdev lantiscooperdev merged commit 4f4339b into main Jun 27, 2026
1 check passed
@lantisprime lantisprime deleted the fix/p5-d5-d6-real-tmux branch June 27, 2026 08:58
lantisprime pushed a commit that referenced this pull request Jun 27, 2026
PR #100 (4f4339b) and PR #101 (07f7057) both touched
agents/P3_IMPLEMENTATION_SLICES.md. Kept PR #101's more complete
version (which mentions PR #100 and both deleted branches).
lantiscooperdev pushed a commit that referenced this pull request Jun 27, 2026
#101)

* fix(tmux-terminal): D5 probe + D6 node prefix (real-tmux execution)

Two bugs surfaced by exercising the implementation against a real tmux
server (test-real-tmux-smoke.mjs). Both invisible to FakeTmuxExecutor
unit tests because the fake returns configurable responses that don't
model the real defaultTmuxExecutor / tmux behavior.

D5 — isAvailable probe (tmux-backend.ts:34)
- Before: `has-session -t __pi_probe__`. The __pi_probe__ session does
  not exist by default, so has-session returns exit 1.
- defaultTmuxExecutor catches non-zero exits and returns {ok: false}.
- The D1 result.ok === true check then made isAvailable always return
  false, even when the tmux server was reachable.
- Fix: probe with `list-sessions` — returns 0 when the server is
  reachable, regardless of session count. Correctly distinguishes
  server-reachable from server-unreachable.
- Test: test-tmux-backend.mjs Group 2 test 1 args assertion updated to
  ["list-sessions"].

D6 — launch argv (tmux-backend.ts:52)
- Before: `["new-window", ..., "--", workerPath, manifestPath]`. tmux
  tried to exec workerPath directly, but bg-worker.ts has no shebang
  and is mode 644 — not executable. The window was created then
  immediately destroyed (the command failed to exec); @pi_run_id and
  @pi_agent_name user-options were never set; isAlive returned false.
- Fix: prepend "node" to argv — `["new-window", ..., "--", "node",
  workerPath, manifestPath]`. node handles the .ts extension via
  --experimental-strip-types (used elsewhere in this repo).
- Tests: test-tmux-backend.mjs Group 3 test 1 deepEqual updated to
  expect "node" prefix; Group 4 test 1 workerIdx indexing updated to
  workerIdx + 2 for manifestPath (intermediate "node" check added).

New: tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs +
      run-real-tmux-smoke.sh
- Exercises the actual createTmuxBackend against an isolated
  `tmux -L p5-smoke-<pid>` socket. Does NOT touch the user's default
  tmux session. Cleans up on exit (kill-server + temp dirs).
- 11 verification steps: backend.name, isAvailable probes real tmux,
  launch creates window, window visible via direct CLI, user-options
  set, isAlive, list recovers runId/agentName, kill removes window,
  isAlive after kill, kill idempotent.
- Skipped (exit 0) if tmux not on $PATH — opt-in by environment.

Docs:
- agents/P3_IMPLEMENTATION_SLICES.md updated with D5/D6 rationale and
  the new real-tmux smoke test entry. Plan v6 should incorporate both
  fixes into the canonical recipe (probe + node prefix).

Why these bugs survived the v5 review (5 rounds) + code review (1 round):
- Plan review focused on argv construction (Group 3 tests), not on
  isAvailable probe semantics or worker-execution semantics.
- Code review verified argv shape against fake-recorded calls but
  did not exercise real tmux.
- Unit tests use FakeTmuxExecutor which returns configurable
  responses; defaultTmuxExecutor's actual return shape (always
  {ok: false} for non-zero exit, no throw) was hidden behind the fake.
- The "Manual smoke: pi -e ./agents/index.ts -e ./tmux-terminal/index.ts
  then /agents bg scout" criterion was listed but never executed before
  merge. The new smoke test makes this criterion mechanically verified.

Verification:
- bash tmux-terminal/test-fixtures/run-p5-tests.sh: 63/63 pass + REQ-13 OK
- bash agents/test-fixtures/run-p4-4-tests.sh: green (regression intact)
- node tmux-terminal/test-fixtures/test-real-tmux-smoke.mjs: 11/11 pass
- Mutation #1 (realpathSync → path.resolve): only testWorkerPathIsRealpathed fails
- Mutation #2 (WORKER_BASENAMES reorder): only testWorkerPathPrefersTsOverMjs fails
- Both mutations revert cleanly

* docs: sync workplan + slices to P5 D5+D6 post-merge (PR #100, 4f4339b)

Three-source sync per workplan-update runbook after PR #100 merged:

1. Episodic memory (canonical-workplan): revised to new episode ID
   20260627-085754-p5-fully-shipped-post-merge-fixes-d5-d6--2ee6
   which supersedes 20260627-083022-p5-tmux-terminal-merged-pr-98-commit-f3b-3d0f
   (the pre-fix merge state). New body documents D5 + D6 fixes, the
   real-tmux smoke test in CI, and points at P5b (zellij/wezterm/headless)
   as the next natural extension.

2. WORKPLAN.md pointer refreshed to the new canonical-workplan episode.
   Tags include p5-pr-98, p5-pr-100, p5-d5-d6-fix.

3. agents/P3_IMPLEMENTATION_SLICES.md top-level P5 entry updated:
   - Added PR #100 + commit 4f4339b next to PR #98
   - Branch line updated to note both p5-tmux-terminal AND
     fix/p5-d5-d6-real-tmux branches deleted post-merge

No code changes. No agent/lib/ changes. Pattern follows PR #99 docs-only
sync PR (also required because main is branch-protected).

---------

Co-authored-by: Charlton D. Ho <dev@znp.pw>
lantiscooperdev pushed a commit that referenced this pull request Jun 27, 2026
…103)

Three-source sync per workplan-update runbook after PR #102 merged:

1. Episodic memory (canonical-workplan): revised to new episode ID
   20260627-092842-p5-fully-shipped-d5-d6-d7-fixes-merged-p-7d1e
   which supersedes the D5+D6-only episode. New body documents D7
   (symlink-loading fix), the full D5/D6/D7 deviation timeline,
   lessons stored globally, and points at P5b as the next natural
   extension.

2. WORKPLAN.md pointer refreshed to the new canonical-workplan episode.
   Tags include p5-pr-98, p5-pr-100, p5-pr-102, p5-d5-d6-fix, p5-d7-fix.

3. agents/P3_IMPLEMENTATION_SLICES.md top-level P5 entry updated:
   - Added PR #102 + commit 6ec1b4b next to PR #100
   - Branches line updated to note all 3 deleted branches

No code changes. No agent/lib/ changes. Pattern follows PR #99 and #101
docs-only sync PRs (also required because main is branch-protected).

Co-authored-by: Charlton D. Ho <dev@znp.pw>
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.

2 participants