orca/tests
Neil f6878d660f
Show Claude's AskUserQuestion card in desktop Chat when the agent runs on a paired headless server (#12223)
* fix(native-chat): show Claude's AskUserQuestion card when the agent runs on a paired headless host

Three gaps kept the question card off the desktop when the agent ran on a
remote `orca serve` host:

- The `session.tabs` projection reduced HTTP agent-hook rows to identity only,
  hard-coding `state: 'done'` and an empty prompt, so `toolName` and the full
  `interactivePrompt` never left the host. It now publishes the newest fresh
  hook row's status fields, bounded by the same staleness window `agentType`
  uses, excluding `providerSessionOnly` resume rows, and yielding to live
  title evidence unless a question is actually pending.
- Nothing republished `session.tabs` when only a hook row changed, and the
  re-emit carried an unchanged `snapshotVersion` that clients drop on their
  monotonic gate. Material hook transitions and pane/SSH status clears now
  bump the version and schedule a coalesced emit.
- The desktop card resolved only from live status. It now falls back to the
  pending ask in the transcript, matching mobile, so a relay gap can no longer
  leave the composer mounted over a pane parked on a selector.

Closes #11761

Co-authored-by: Orca <help@stably.ai>

* fix(native-chat): date the hook-row recency guard against a real clock

`resolveHookLiveAgentRow` compared a hook `receivedAt` (epoch ms) against
title stamps that are title-observation sequence numbers, so the guard could
never fire — any fresh hook row overrode live title-derived state, and a manual
rename (the one epoch writer) inverted it. Stamp the live OSC title path with
wall-clock ms and compare against that alone.

The regression test fabricated epoch-valued title stamps production never
writes; it now drives the title through `onPtyData`, and a new case pins the
opposite direction (hook row newer than the title wins).

Co-authored-by: Orca <help@stably.ai>

* fix(native-chat): stop an orphaned tool call from pinning a dead question card

extractPendingAsk pairs tool results to calls by a global FIFO (tool_use_id
is dropped at decode time), so one call that never gets a result desyncs the
queue for the rest of the transcript and strands an answered ask as pending.
Real transcripts also hold asks the user escaped and typed past. On desktop
that card replaces the composer, so the pane became unsendable.

Drop in-flight calls at a turn boundary — a user turn or the decoders'
interrupt row — since the turn that owned them is over. Claude's tool-result
turns decode as role 'tool', so normal FIFO resolution is untouched.

Co-authored-by: Orca <help@stably.ai>

* refactor(native-chat): trim the headless AskUserQuestion projection

Reuse rather than restate: the invalidator now takes the shared
`AgentHookEventPayload` instead of a locally redeclared row shape, and the
hook live row is a `Pick<>` of the retained OSC snapshot so one projection
branch consumes either carrier. Fold the immediate/coalesced session-tabs
emit into one method (also drops a redundant re-emit on the
provider-session push). Drop card tests that re-route shared-parser
assertions through React. Isolate pane-status-clear subscribers and prove
the no-republish case by version arithmetic instead of a timed silence.

Co-authored-by: Orca <help@stably.ai>

* test(native-chat): pin the AskUserQuestion card render under real Electron

Why: the 13 parser unit tests pin extraction, but nothing proved a card
actually renders where an inert tool call used to. This spec reproduces the
paired-headless topology from the client side — live status carrying agent
identity and state 'working' but no interactivePrompt/toolName, with the
pending ask present only in the transcript — and fails on main.

Refs #11761

Co-authored-by: Orca <help@stably.ai>

* test(native-chat): drop the unused testInfo parameter

Why: oxlint no-unused-vars fails the lint gate on an unused test parameter.

Co-authored-by: Orca <help@stably.ai>

* test(native-chat): drop leftover proof scaffolding from the ask-card spec

The env-var screenshot label and the fixed 2s settle only existed to make
the pre-fix capture comparable; the card assertion already waits.

Co-authored-by: Orca <help@stably.ai>

* test(runtime): use a truly unresolvable pane key in the hook republish guard

#11203 taught pane lookup to recover a reminted tab id by leaf id, so the old
fixture (new tab id, live leaf id) resolved and bumped the snapshot a second
time once this branch merged with main.

Co-authored-by: Orca <help@stably.ai>

* fix(runtime): refuse a hydrated unconfirmed hook row as live pane status

#12346 landed on main after this branch was cut: a nonterminal row restored from
last-status.json is stamped `restoredUnconfirmed` because its transition may have
fired while no receiver was up, and every freshness gate treats it as never-fresh.
The new headless `live` projection here only checked `receivedAt`, so a restart
inside the 30-minute window would republish the hydrated row — resurrecting the
AskUserQuestion card with no agent left to answer it.

`agentType` still reads those rows: they prove identity, just not liveness.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Neil <nwparker@users.noreply.github.com>
2026-08-04 00:48:58 -07:00
..
e2e Show Claude's AskUserQuestion card in desktop Chat when the agent runs on a paired headless server (#12223) 2026-08-04 00:48:58 -07:00
tools fix(runtime): coalesce concurrent host terminal focus (#11841) 2026-08-03 02:18:05 -07:00
.gitignore feat: add idempotent E2E test suite with headless Electron support (#671) 2026-04-19 12:09:32 -07:00
playwright.config.ts Stabilize sharded e2e CI concurrency (#6312) 2026-06-24 18:39:02 -07:00