Repository navigation
fix(bin): stop desk-voice delivery from scrolling the Firstmate chat - #270
Merged
Merged
Conversation
The send path's selection-dialog, chat-box and stash checks read the pane with a history capture. On herdr, a line-counted read of an idle Claude pane makes herdr scroll Claude's conversation up to collect its history and back, which shows as the chat jumping while a voice or dictated message is delivered. Those checks now read only the visible screen wherever the backend has a verified viewport read, as the composer check already does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
yes sure go for option 1. His no-mistakes should have done those checks no? He should have parity of what we have here.
Context: option 1 means taking Luc Wächter's (GitHub lwachter-code) fix from his fork pull request #269, "fix(bin): stop desk-voice delivery from scrolling the Firstmate chat", and raising it again through this repo's own no-mistakes pipeline so it gets the full checks (including lint), crediting Luc, then closing his pull request with thanks. His pipeline could not push to this repo (no write access, so he opened the PR from his fork by hand) and its lint step was skipped because ShellCheck was not installed on his machine; the PR has no CI runs.
The change: on Herdr 0.9.3 a line-counted history read (
pane read --source recent --lines 200) of an idle Claude pane makes Herdr scroll Claude's conversation up and back, visible as the chat jumping while the desk floater shows "Delivering". In bin/fm-desk-voice.sh the send path's selection-dialog, chat-box (composer_text) and stash checks now read only the visible screen wherever fm_backend_visible_capture_supported holds, via a new screen_rows helper; other backends keep the bounded history capture. New test test_desk_voice_send_reads_only_the_visible_screen in tests/fm-deepgram-desk.test.sh.What Changed
bin/fm-desk-voice.shgets a newscreen_rowshelper that returns the last N rows of a pane. It reads only the visible viewport (fm_backend_visible_capture) on backends wherefm_backend_visible_capture_supportedholds. On all other backends it falls back to the existing bounded history capture (fm_backend_capture). This matters on Herdr 0.9.3: a history read (pane read --source recent --lines …) of an idle Claude pane scrolls the conversation up and back while the floater shows "Delivering".screen_rowsinstead offm_backend_capture: the selection-dialog check (shows_selection_dialog), the chat-box check (composer_text) and the stash check (shows_stash). The row limits and their fail-safe defaults stay the same.test_desk_voice_send_reads_only_the_visible_screentotests/fm-deepgram-desk.test.sh. It covers two cases, sending past a Claude draft and sending with a picker dialog open, and checks that no Herdrpane readcall asks for--linesor--source recent. In the picker case it also checks that the words go to the mailbox instead.Credit: originally written by Luc Wächter (@lwachter-code). This supersedes #269, raised again here through this repo's no-mistakes pipeline so it gets the full checks; his commit and authorship are kept.
🤖 Generated with Claude Code
Risk Assessment
✅ Low: Three read-only screen checks now share one small helper. The helper reads only the visible screen wherever the backend has a verified viewport read, which is the same read herdr's own composer and payload checks already use, and every other backend still gets the bounded history capture. A failed or empty read fails safe: the message goes to the mailbox and the draft is kept. The regression test drives the public send command and checks the logged herdr calls, and both of its cases would fail on the base commit.
Testing
I ran the new regression test on the change and on the base code. It passes with the change, fails on base, and its dialog half fails if only the dialog check reads history again. I then drove the real desk-voice send against real Claude primaries in a tmux lab and a Herdr 0.7.4 lab. Messages were delivered, a typed draft was set aside and put back, and an open picker got nothing; the message went to the mailbox. Every screen check read only the viewport, while the base script made 6 history reads per send. Both labs were torn down. I saved text captures of the real panes and logs of the tmux/herdr calls; no screenshot was taken because the surface is a terminal pane and the before/after captures show the actual screen. The chat jump itself only happens on Herdr 0.9.3, which is not installed here, so that part is untested.
sent: herdr fm-lab-...:w1:p1, Claude replied HERDRPONG, draft restored; herdr calls show only--source visible. Base script on the same pane made 6x `--…sent: tmux %0, PONG/DRAFTPONG replies, draft restored; change makes 6xcapture-pane -S -0, base made 6xcapture-pane -S -20mailbox: .../inbox/20261008T080336Z-dadf258f.json, picker screen unchanged before and after, no send-text/send-keys callstested: ok on t…herdr --version), and the scroll-on-history-read bug only happens on Herdr 0.9.3. On 0.7.4 the live viewport poll showed only forward content growth with both the base…Evidence: Herdr live: send past a draft with the change, herdr calls (visible reads only)
Source: Herdr live: send past a draft with the change, herdr calls (visible reads only)
Evidence: Herdr live: same send with the base script (6x --source recent --lines 200)
Source: Herdr live: same send with the base script (6x --source recent --lines 200)
Evidence: Herdr live: Claude pane before the send (draft typed)
Source: Herdr live: Claude pane before the send (draft typed)
Evidence: Herdr live: Claude pane after the send (HERDRPONG reply, draft restored)
Source: Herdr live: Claude pane after the send (HERDRPONG reply, draft restored)
Evidence: Herdr live: viewport top rows and scroll offset polled during the send
Source: Herdr live: viewport top rows and scroll offset polled during the send
Evidence: Herdr live: /model picker open, send goes to mailbox, picker unchanged
Source: Herdr live: /model picker open, send goes to mailbox, picker unchanged
Evidence: tmux live: send past a draft with the change (capture-pane -S -0 only)
Source: tmux live: send past a draft with the change (capture-pane -S -0 only)
Evidence: tmux live: same send with the base script (capture-pane -S -20)
Source: tmux live: same send with the base script (capture-pane -S -20)
Evidence: tmux live: Claude pane after send past draft (DRAFTPONG reply, draft restored)
Source: tmux live: Claude pane after send past draft (DRAFTPONG reply, draft restored)
Evidence: Pane reads per send-past-draft on the live Herdr pane
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
sent: herdr fm-lab-...:w1:p1, Claude replied HERDRPONG, draft restored; herdr calls show only--source visible. Base script on the same pane made 6x `--…sent: tmux %0, PONG/DRAFTPONG replies, draft restored; change makes 6xcapture-pane -S -0, base made 6xcapture-pane -S -20mailbox: .../inbox/20261008T080336Z-dadf258f.json, picker screen unchanged before and after, no send-text/send-keys callstested: ok on t…herdr --version), and the scroll-on-history-read bug only happens on Herdr 0.9.3. On 0.7.4 the live viewport poll showed only forward content growth with both the base…tests/fm-deepgram-desk.test.shfocused run (temporary runner, since removed): test_desk_voice_send_reads_only_the_visible_screen, test_desk_voice_send_goes_past_a_claude_draft, test_desk_voice_send_falls_back_when_the_pane_shows_a_dialog, test_desk_voice_send_keeps_a_draft_it_cannot_set_aside: all ok on the changeSame regression test with basebin/fm-desk-voice.sh(fc0eda7d) swapped in: fails withnot ok - a send past a draft never asks herdr for history (unexpected: '--lines')Dialog half alone, change vs. change with only shows_selection_dialog reverted to fm_backend_capture: ok vs.not ok - the dialog check never asks herdr for historyLive tmux lab (bin/fm-lab-home.sh create,tmux -L fm-lab new-session ... claude, primary took the lock viabin/fm-lock.sh):fm-desk-voice.sh sendwith an empty chat box, logging tmux through a pass-through wrapperLive tmux lab:fm-desk-voice.sh sendpast a real typed Claude draft, on the change and then on the base scriptLive Herdr lab (bin/fm-herdr-lab.sh provision/run/teardown, Herdr 0.7.4, real claude in pane w1:p1 holding the lab lock):fm-desk-voice.sh sendpast a typed draft on the change and on the base script, logging herdr calls through a wrapper and polling the visible top rows and scroll offset during the sendLive Herdr lab, adversarial:fm-desk-voice.sh send 'sonnet please'while Claude's real/modelpicker was openTeardown:bin/fm-herdr-lab.sh teardown,tmux -L fm-lab kill-server,rm -rfof both lab homes; worktree left clean✅ **Document** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.