Skip to content

fix(tmux): refuse text dropped by composer - #2800

Closed
SimTet wants to merge 3 commits into
kunchenguid:mainfrom
SimTet:fm/fm-tmux-preexisting-failures
Closed

SimTet wants to merge 3 commits into
kunchenguid:mainfrom
SimTet:fm/fm-tmux-preexisting-failures

Conversation

@SimTet

@SimTet SimTet commented Aug 22, 2026

Copy link
Copy Markdown

Intent

Diagnose and fix the captain-reported pre-existing tmux-related failure in Firstmate from a clean upstream base: fm-send can report success after literal text sent to an interactive prompt is discarded while Enter answers the prompt default. Establish the exact failure and distinguish pre-existing upstream behavior from environmental availability, accidental local edits, intentionally opt-in live tests, and the concurrent fm-terminal-runtime-retirement task. Implement only confirmed independent tmux defects at the earliest causal boundary, without copying or competing with that concurrent task’s terminal-retirement contract. Add executable regression coverage through public/script interfaces, never implementation-source assertions; prove both refusal when a prompt drops typed text and normal submission when the composer accepts it. Preserve tmux endpoint identity, composer safety, task isolation, no-unlanded-work, remote-secondmate behavior, watcher continuity, cross-platform behavior, and all unaffected supported runtime-backend contracts. Review all call sites and backend impact; update only authoritative current documentation if behavior or an empirical guarantee changes. Require focused tmux regressions and relevant portable backend suites, bin/fm-lint.sh, and bin/fm-doc-audience-check.sh to pass. The independent implementation is committed as 7a97984 on fm/fm-tmux-preexisting-failures. Validate, push, and open a separate PR; never merge.

What Changed

  • Require tmux submissions to observe the typed payload appended to the selected composer content, including when a draft already exists, before pressing Enter.
  • Return a not-accepted refusal without Enter when composer input is dropped, and propagate it through send, exit, and Kimi brief-submission flows.
  • Document the composer-acceptance guarantee and add regression coverage for dropped text, stale drafts, normal submission, and affected backend paths.

Risk Assessment

✅ Low: Captain, the scoped tmux change now proves a full composer append before Enter, safely propagates refusal outcomes, and preserves supported delivery paths.

Testing

Focused tmux, portable backend/control, and remote-delivery regressions passed. Live tmux evidence reproduces the base defect (exit 0 plus DEFAULT_ANSWERED), verifies target refusal without Enter (exit 1 and no default), and verifies normal accepted-composer submission (exit 0). Lint and documentation static checks were not run because this assigned test phase explicitly prohibits linters and static analysis.

Evidence: Live tmux prompt regression transcript

Source: Live tmux prompt regression transcript

Live tmux interactive-prompt transcript (tmux 3.2a)
The prompt discards literal keys; Enter explicitly chooses DEFAULT_ANSWERED.

[baseline-live] exit=0 default-result=DEFAULT_ANSWERED
pane after fm-send:
❯
DEFAULT_ANSWERED
❯
fm-send diagnostic:
WARNING: watcher still down (same stale episode; last beat: never, grace 300s) - full banner already printed this episode.

[target-live] exit=1 default-result=
pane after fm-send:
❯
fm-send diagnostic:
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  1 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the requested message WILL still be sent.
●  repair missing watcher supervision with a foreground checkpoint: bin/fm-watch-checkpoint.sh --seconds 180.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
error: text not accepted into the composer at nm-live-prompt-target-live-31964:0 (harness=claude; backend=tmux); no Enter was sent, so an interactive prompt was not answered. Inspect with fm-peek.sh before retrying.
Evidence: Live tmux accepted-composer transcript

Source: Live tmux accepted-composer transcript

Live tmux accepting-composer transcript (tmux 3.2a)
[target-live-composer] exit=0 submitted-result=SUBMITTED:continue with the requested work
pane after fm-send:
❯ continue with the requested work
SUBMITTED:continue with the requested work
❯
fm-send diagnostic:
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●  WATCHER DOWN - SUPERVISION IS OFF
●  1 task(s) in flight, but no watcher has a fresh beacon (last beat: never, grace 300s).
●  Trust the emitted supervision protocol for this harness; do not use shell & for watcher repair.
●  This is a supervision warning only; the requested message WILL still be sent.
●  repair missing watcher supervision with a foreground checkpoint: bin/fm-watch-checkpoint.sh --seconds 180.
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 4 issues found → auto-fixed ✅
  • 🚨 bin/fm-tmux-lib.sh:307 - The new proof only looks for the payload tail after typing, so it cannot establish that this send actually changed the composer. If a modal drops the literal while a visible stale draft already contains the same tail (or merely contains a short tail as a substring), this check succeeds and line 311 still sends Enter to the modal. fm-send has no empty-composer preflight, and the sibling Zellij adapter already treats pre-existing intended text as insufficient by requiring an observed append. Capture selected composer content before send-keys and require the post-send content to be that same selection with the normalized payload appended; add the stale-draft/modal case through fm-send and assert no Enter.
  • ⚠️ bin/fm-tmux-lib.sh:308 - not-accepted is a definitive no-delivery result, but the shared caller fm-control.sh only rejects send-failed; it therefore waits and reports exit-command=delivered even though this new path explicitly sent no Enter. Handle not-accepted as an immediate failed lifecycle delivery (and audit the other non-fm-send callers of the backend verdict) so the newly introduced result cannot be misreported.
  • ⚠️ bin/fm-composer-lib.sh:1196 - The anchor normalizer deletes every box-drawing character, then rejects an empty result. A legitimate literal message made solely of these characters (for example ────) is therefore refused even when the composer visibly accepted it, contradicting the required normal-submission behavior for literal text. Preserve content characters after selected-composer extraction; only strip actual structural furniture.
  • 🚨 docs/tmux-backend.md:85 - User intent requires “update only authoritative current documentation if behavior or an empirical guarantee changes.” The diff adds a new pre-Enter payload-acceptance refusal, while this authoritative tmux-backend description still says only that a message is typed once and Enter is retried until the composer clears. No documentation hunk records the new refusal guarantee or recovery behavior. Should this contract be added here before merge?

🔧 Fix: Harden tmux composer append verification
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • bin/fm-test-run.sh tests/fm-tmux-submit-busy.test.sh tests/fm-send-strict.test.sh tests/fm-backend.test.sh tests/fm-control.test.sh tests/fm-control-relaunch.test.sh tests/fm-send-popup-settle.test.sh tests/fm-send-remote-delivery.test.sh tests/fm-send-resolve-key.test.sh tests/fm-send-settle.test.sh
  • bash tests/fm-control.test.sh
  • bash tests/fm-control-relaunch.test.sh
  • bash tests/fm-send-popup-settle.test.sh
  • bash tests/fm-send-remote-delivery.test.sh
  • bash tests/fm-send-resolve-key.test.sh
  • bash tests/fm-send-settle.test.sh
  • Live tmux 3.2a public fm-send.sh runs against an interactive prompt that discards text and whose Enter selects DEFAULT_ANSWERED, using both base and target scripts.
  • Live tmux 3.2a public fm-send.sh run against an accepting composer; persisted result is SUBMITTED:continue with the requested work.
  • Temporary live tmux sessions were terminated; git status --porcelain remained empty.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@greptile-apps

greptile-apps Bot commented Aug 22, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge, with no concrete changed-code defect identified.

The new refusal verdict is handled by every production submission caller, and the tmux path withholds Enter when it cannot prove that the selected composer accepted the payload.

Reviews (1): Last reviewed commit: "no-mistakes(document): Document tmux com..." | Re-trigger Greptile

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