Skip to content

[Bug]: Send-notes offer path and terminal.agentStatus pre-check derive agent aliveness independently (structural offer-then-refuse) #26568

Open

Description

@bashrusakh

Operating system

Windows (original report); the gap itself is platform-independent

Orca version

v1.4.217 (original report); verified against main @ 7c50009ca4946cf7384495f542d0b5856308b70c

Details

Short summary: the "Send notes to" target list and the send pre-check answer "is an agent alive in this pane?" with two independent derivations. When they disagree, a target is offered and then refused — the structural remainder of #24286 that would remain even if the proposed spinner-title fix #25513 lands. #25513 is open, not merged: main @ 7c50009c still accepts a lone quarter-circle title in detectAgentSendTitleStatus, so the guard exists only inside that PR — and this gap is independent of it, because the mismatch below lives in the status-store lane and the runtime verdict, neither of which goes through the title lane.

The two derivations (file:line on main @ 7c50009c):

  • Offer: deriveTerminalAgentSendTargets (src/renderer/src/lib/running-agent-targets.ts:84-162) iterates the renderer's hook store (agentStatusByPaneKey, 30-minute freshness via pane-agent-evidence.ts) plus a live-title override. It never consults isRunningAgent.
  • Refusal: src/renderer/src/lib/active-agent-terminal-send-readiness.ts:32-44 → terminal.agentStatus → !isRunningAgent → 'no-agent'.
  • isRunningAgent derivation: terminal-query-methods.ts:104-110 → runtime-terminal-agent-status-query.ts:69-139 (permission-title / blocked-text / hook-status branch / title-status branch / presence-engine fallback). Hook rows are stale after 30 minutes (AGENT_STATUS_STALE_AFTER_MS, src/shared/agent-status-freshness.ts).

Nothing keeps the two sides consistent: any pane whose renderer-store evidence is fresher than what the main-process derivation accepts can be offered and then refused with no lane that reconciles them.

Historical reproduction (v1.4.217 — not evidence against current main): Viy1204's Antigravity case in #24286 (see issuecomment-6051319515):

  • pane titled C:\Program Files\PowerShell\7\pwsh.exe, agentIdentity: "antigravity" from the foreground-process check (detectCmd: 'agy');
  • hook status (agent-hooks/last-status.json) never written for a fresh pane, one stale Stop (8 days old) for the original pane;
  • the pane shows up in the send menu, then the pre-check refuses with no-agent.

Caveats from the reporter, kept intact: measured on v1.4.217, which predates #24222 / #24348 (screen-readiness for Antigravity; first release containing them is v1.4.220), so the tui-idle timeout half of his report is the already-fixed #24486 symptom and needs a re-test on ≥ v1.4.220 before it counts against current code. He also could not read isRunningAgent directly. And on current main a pane without a fresh explicit status falls back to isTerminalRunningAgent() → the presence engine, which recognizes the foreground process via recognizeAgentProcess (detectCmd: 'agy', shared/tui-agent-config.ts) — so agentIdentity: "antigravity" observed on 1.4.217 does not imply that current terminal.agentStatus also returns false. The offer-then-refuse pair must be re-reproduced on a current build before it counts as a current bug; the structural gap above rests on the code paths alone.

Open questions (design, not yet decided):

  1. Should offer eligibility and the send pre-check consult one shared derivation of "agent aliveness here", instead of a renderer copy that can drift from the runtime verdict?
  2. For Antigravity on Windows specifically: is the hook channel expected to ever write fresh rows for agy? If not, both sides must fall back to process/screen evidence — related to [Bug]: Windows: Antigravity (agy) sessions missing from sidebar — orca-status bundle wiped from ~/.gemini/config/hooks.json and never reinstalled #17672 (hooks.json wiped and never reinstalled on Windows).

Related: #24286 (original; Refs only — its spinner-title lane is addressed by #25513, open and unmerged), #24486 (tui-idle screen read, fixed in v1.4.220), #17672 (Windows hooks installation).

Activity

  1. bashrusakh commented on Oct 8, 2026

    @bashrusakh
    Author

    Proposed fix direction: make Send Notes eligibility runtime-authoritative

    I would fix this at the Send Notes authority boundary, rather than by adding another renderer-side heuristic or by attempting a repo-wide unification of all agent-presence semantics.

    The core problem is not a single missing condition. Today, two independent paths answer effectively the same product question:

    Renderer:
    agentStatusByPaneKey + title + PTY
        -> target is offered as eligible
    
    Runtime:
    hook status + title + foreground process + presence rules
        -> terminal.agentStatus
        -> send is allowed or refused
    

    As long as those remain independent derivations, they can drift. Fixing individual mismatches in the renderer only moves the divergence point.

    Proposed authority model

    For Send Notes, the runtime should be the single authority for:

    “Can Orca safely send input to this terminal as an agent right now?”

    The renderer may still perform candidate discovery, but it should not independently make the final eligible decision.

    Conceptually:

    Renderer discovers candidate terminal
                  |
                  v
          terminal.agentStatus
                  |
                  v
            Runtime authority
                  |
            +-----+------+
            |            |
         eligible      disabled
                        |
              no-agent / permission / unavailable
    

    The final send-time guard should remain in place and call the same runtime authority again, because terminal state may change between opening the menu and clicking Send.

    Suggested separation of responsibilities

    deriveTerminalAgentSendTargets should answer:

    “Which terminal panes are plausible Send Notes candidates?”

    It should not be the final authority for:

    “Is this terminal currently safe and valid to send to?”

    The latter should come from the runtime.

    That would turn the current flow from:

    renderer heuristic -> eligible
    
    runtime heuristic  -> no-agent
    

    into:

    renderer discovery
           |
           v
    runtime readiness -> menu eligibility
           |
           v
    runtime readiness -> final send guard
    

    Why not copy more runtime checks into the renderer?

    That would preserve the underlying problem.

    The runtime presence decision can depend on evidence such as:

    • fresh hook state
    • terminal title
    • foreground process
    • launch identity
    • ready-prompt evidence
    • agent-specific presence rules

    The renderer does not necessarily have all of that evidence, and duplicating the runtime rules would create another implementation that must remain synchronized indefinitely.

    A local patch such as adding the current shell-title rejection to the renderer may fix one reproduction while leaving the same structural failure mode available through another evidence combination.

    Why not introduce one global isAgentAlive() abstraction for all Orca consumers?

    That seems broader than necessary for this issue.

    Different consumers legitimately ask different questions:

    Sidebar:
    “Is there agent activity worth displaying?”
    
    Worktree status:
    “What status should be shown?”
    
    Permission handling:
    “Is the agent waiting for user action?”
    
    Send Notes:
    “Is it safe to submit input to this terminal now?”
    

    Those do not necessarily need identical evidence or policy.

    So I would avoid turning #26568 into a global agent-state refactor. The narrower invariant needed here is:

    All Send Notes decisions that authorize input should share the same runtime authority.

    Concrete invariant

    After the fix, this should not be possible purely because the renderer and runtime interpreted agent presence differently:

    Send Notes menu: eligible
    Send pre-check:   no-agent
    

    A target may still become invalid between discovery and send because state changed, which is why the final guard remains necessary. But the menu and the send guard should not disagree because they use different definitions of agent presence.

    Scope

    This is intentionally between two extremes:

    • not a one-off Antigravity-specific fix;
    • not a repo-wide agent-state redesign.

    The proposed scope is:

    Make Send Notes terminal eligibility runtime-authoritative, while keeping renderer-side logic for discovery and presentation only.

    That removes the structural offer-then-refuse class without weakening the existing fail-closed send guard.

  2. AmethystLiang commented on Oct 8, 2026

    @AmethystLiang
    Contributor

    Thanks for reporting. Looking into it

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions