Skip to content

Pending messages: a session replaced inside the same pane is not noticed when the agent reports no native session #540

Closed as not planned

Description

@devswha

Found by a Codex adversarial pass during the review of #520 (bridge-owned pending messages). Not fixed there; reported here so it is not lost. It does not block #520.

What happens

A pending message is bound to the pane's agent by pendingIdentity() in server/index.ts: the agent name, the terminal_id, and herdr's native agent_session (kind:source:value), or null when herdr reports none. Before the paste and before Enter, pendingContext() compares that identity with the pane's current one and refuses with pending_target_changed when they differ.

For an agent without a native session reference both sides are agent / same terminal / null, so a session change inside the same pane is not seen:

  • An OmO pane. OmoStatus (server/omo-status.ts) does discover the session (sessionOf()), but apply() projects only the agent name and status into the snapshot, so the discovered session never reaches the comparison.
  • A hookless Claude Code pane (server/claude-session.contract.test.ts, "reads each hookless Claude pane's own conversation in a shared cwd": agent_session is undefined).

Sequence: a connection queues a message while the agent works. The session in that pane is replaced (a new session started from the terminal or another client, a resume) while the pane and the attachment stay. When the new session becomes ready, the bridge delivers the old session's message into it.

Impact

The message goes to the same pane, the same agent process and the same user, but into a different conversation. No other connection gains anything.

Why it was left out of #520

  • Pinning OmO's discovered session can hold a message wrongly when the session is discovered only after the message was queued (null at enqueue, known at delivery).
  • A hookless Claude pane has no stable identity to pin at all, so "refuse when no identity can be established" would turn the feature off for it.

Possible fix

  • Carry the discovered session identity into pendingIdentity() where one exists (OmO), and compare only when both sides know it.
  • Decide what a pane with no identity at all should do: deliver as today, or hold for an explicit Send now once anything suggests the session changed (for example a transcript file that is not the one read at enqueue).
  • A contract test that changes the session without replacing the attachment.

Activity

  1. devswha commented on Oct 16, 2026

    @devswha
    OwnerAuthor

    Partly fixed by #1069 (38d6863): a process replaced in the same pane (pid/birth) and a different OmO session are now held. Remaining: a /clear or resume inside the same process, by an agent that reports neither a native nor an OmO session, and Windows panes where herdr reports no foreground process.

  2. devswha commented on Oct 19, 2026

    @devswha
    OwnerAuthor

    Partly fixed again by #1310: a queued message is now held when Claude Code switches session inside the same process (/clear, resume). Still open: the same in-process switch for an agent that reports neither a native nor an OmO session, and Windows panes where herdr reports no foreground process.

  3. devswha commented on Oct 19, 2026

    @devswha
    OwnerAuthor

    Closing as not planned. #1069 holds a queued message when the pane's process is replaced or the OmO session changes, and #1310 when Claude Code switches session inside the same process. What remains is an in-process session switch by an agent that reports neither a native nor an OmO session, and Windows panes where herdr reports no foreground process. For a queued message this is a sub-second race in practice: agents generally refuse a new session while working, and the message is delivered as soon as the agent goes idle. A held message is sent only on an explicit Send now. Closing the gap needs session identity from herdr or the agent. Reopen if that becomes available or a real case is reported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions