Skip to content

fix(messages): gate inbound msg on pending UI + always repost card#88

Merged
Time4Mind merged 1 commit into
mainfrom
fix/inbound-msg-ui-race-and-card-repost
May 17, 2026
Merged

fix(messages): gate inbound msg on pending UI + always repost card#88
Time4Mind merged 1 commit into
mainfrom
fix/inbound-msg-ui-race-and-card-repost

Conversation

@Time4Mind
Copy link
Copy Markdown
Owner

Summary

Two adjacent races/inconsistencies in the inbound-message path, observed in session local_bot today:

  • Pending interactive UI consumed user keystrokes. When an AskUserQuestion / ExitPlanMode / Permission prompt was on the pane and status_polling hadn't surfaced the kb-mode keyboard yet (1-second poll cadence), a user-typed message went straight to send_to_window and got interpreted as menu navigation — digits selected options, Enter submitted, kb-mode never appeared in TG. The old guard in text_handler detected the UI but fell through to send the text anyway.
  • Live card didn't repost after photo / voice / document / caption / slash. text_handler already runs the resume_card_view + repost_intent + repost_card bracket so the card lands below the user's message; the other inbound paths skipped it, leaving the card pinned above the user's file/caption.

Changes (src/ccbot/bot/messages.py)

  • New _intercept_if_pending_ui(bot, user_id, wid, reply_to) — captures pane, surfaces via enter_kb_mode (active session) or handle_interactive_ui (orphan/bg), notifies user, returns True. Caller returns on True instead of sending.
  • New _card_repost_bracket(bot, user_id, sess) async-context-manager with a commit() handle. Failed sends skip the repost; successful ones spawn a fresh card below the user msg and drop the old one.
  • Applied to: text_handler (intercept only — repost bracket already inline), voice_handler, photo_handler, document_handler, caption-forward in unsupported_content_handler, forward_command_handler.
  • Old text_handler guard (which detected UI but didn't return) removed.

Test plan

  • uv run ruff check src/ tests/ — clean
  • uv run pyright src/ccbot/ — 0 errors
  • uv run pytest tests/ — 473 passed
  • Manual: send AskUserQuestion in a session, then a TG text mid-pane → kb-mode surfaces, text stays in TG, pane untouched
  • Manual: send a photo with an attached caption → fresh card spawned below the photo, old card dropped
  • Manual: forward a /slash command → card reposts below

🤖 Generated with Claude Code

Two adjacent races/inconsistencies in the inbound-message path:

1. **Pending interactive UI consumes user keystrokes.** When an
   AskUserQuestion / ExitPlanMode / Permission prompt was on the
   pane and status_polling hadn't surfaced it yet (1-second poll
   cadence), a user-typed message went straight to send_to_window
   and got interpreted as menu navigation — digits selected
   options, Enter submitted, kb-mode keyboard never appeared in
   chat. The old guard in text_handler detected the UI but fell
   through to send the text anyway.

   New helper ``_intercept_if_pending_ui`` captures the pane, and
   on detection surfaces the prompt via ``enter_kb_mode`` for the
   active session (or the legacy floating-msg fallback for orphan
   / bg windows), notifies the user, and returns True. All
   inbound handlers (text / voice / photo / document / caption /
   forwarded slash) now ``return`` on True instead of sending.

2. **Live card didn't repost after photo / voice / document /
   caption / slash.** ``text_handler`` already runs the
   resume_card_view + repost_intent + repost_card bracket so a
   fresh card lands below the user's message and old one drops;
   the other inbound paths skipped it, leaving the card pinned
   above the user's file/caption.

   New async-context-manager ``_card_repost_bracket`` factors the
   pattern out (with a ``commit()`` handle so failed sends skip
   the repost). photo_handler, document_handler, voice_handler,
   caption-forward in unsupported_content_handler, and
   forward_command_handler now wrap their send_to_window /
   _forward_inbox_file calls in it.

Tests: ``test_forward_command.py`` mocks gain ``capture_pane`` →
empty string and ``find_session_by_window`` → None so the new
guard + bracket no-op.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Time4Mind Time4Mind merged commit bb37c31 into main May 17, 2026
4 checks passed
@Time4Mind Time4Mind deleted the fix/inbound-msg-ui-race-and-card-repost branch May 17, 2026 11:05
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