[Bug]: preview_wait_for still evicts a live host when its miss reply lands at the broker deadline

Open
#12,898 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
68/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript

Research direction

Start with apps/server/src/mcp/toolkits/preview/handlers.ts and apps/server/src/mcp/PreviewAutomationBroker.ts, then compare the desktop behavior in apps/desktop/src/preview/Manager.ts. Run the relevant PreviewAutomationBroker.test.ts coverage and reproduce a wait whose miss reply arrives at the deadline. Done means an operation-level timeout leaves the host registered and its session tab assignment usable for the next preview operation.

Written by the indexing model from the issue text.

Description

Before submitting
  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.
Area

apps/server

Steps to reproduce
  1. Run t3 0.0.43-nightly.20260921.2044 (or current main) with the desktop app connected as the preview automation host.
  2. From an agent thread, preview_open a page and preview_type into a field so the tab is pinned to this session.
  3. Call preview_wait_for with { "text": "<text that never appears>", "timeoutMs": 5000 }.
  4. After it fails, call preview_type or preview_status in the same thread.
Expected behavior

Step 3 returns PreviewAutomationTimeoutError for the wait. The desktop host stays registered and pinned, so step 4 runs on the same tab.

Actual behavior

Step 3 returns PreviewAutomationTimeoutError at the 5 s mark. The broker has already evicted the host. Step 4 returns PreviewAutomationNoAvailableHostError. On the deployed nightly the host is gone until the desktop app reloads. On main with #12535 the host re-registers about one second later, but the tab assignment for the session is dropped and the in-flight wait counts as a dead-host eviction.

Cause, on current main:

  • apps/server/src/mcp/toolkits/preview/handlers.ts forwards the same input.timeoutMs as the broker deadline and as the desktop operation timeout (preview_wait_for: (input) => invokeTargeted("waitFor", input, input.timeoutMs)).
  • apps/desktop/src/preview/Manager.ts performAutomationWaitFor polls while (now <= deadline) with sleep(100) and only then fails with the operation-level PreviewAutomationTimeoutError. Its reply is always at or after timeoutMs.
  • apps/server/src/mcp/PreviewAutomationBroker.ts fires Effect.timeoutOption(timeoutMs) first and calls disconnect(...), so the honest miss reads as an unanswered host.

This is the race that #12407 described. That issue was closed by its reporter on 2026-09-18 without a fix. The triage comment on it accepted the bug (bug, accepted). main at 1de563c14 (2026-09-21) still has the same handler line and the same broker deadline. #11381 states the intended contract: "A host that replies with an operation-level timeout remains available." PreviewAutomationBroker.test.ts covers that only when the host replies immediately.

Impact

Major degradation or frequent failure

Version

Server: t3 v0.0.43-nightly.20260917.1866 (reproduced). Desktop client: 0.0.43-nightly.20260921.2044. Same code path on main at 1de563c14.

Environment

Linux x86_64 server (Proxmox VM), Node 24.19.0. Desktop on macOS. Agent: Cursor via ACP inside T3 Code.

Evidence

Provider event log for one thread on 2026-09-21 (UTC). The waitFor had timeoutMs: 5000.

10:52:44.786 preview_type   {locator:"role=textbox[name='Search library']", text:"Fire"}  ok
10:52:53.606 preview_wait_for {text:"Fire Safety", timeoutMs:5000}               started
10:52:58.709 preview_wait_for                                                     PreviewAutomationTimeoutError (5.1 s)
10:53:03.566 preview_type   {locator:"role=textbox[name='Search library']", text:"QA"}
10:53:03.610 preview_type                                                         PreviewAutomationNoAvailableHostError
10:53:07.912 preview_status                                                       PreviewAutomationNoAvailableHostError

The same pair happened at 00:42:52 and 00:42:57 the same day with a 45 s wait. A preview_click that failed fast at 10:51:21 did not drop the host.

Related issues
  • #12407: same race, closed by the reporter without a fix. This report asks for it to be reopened or replaced.
  • #11381: added the eviction and the "operation-level timeout keeps the host" contract.
  • #12535: re-registers the host after eviction. It does not stop the eviction, and it drops the session's tab assignment.
  • #12146: the "never reconnects" symptom on older builds. Fixed by #12535.
  • #12273 / #12279: the optional 500 ms metadata timeout path. Different call site, same broker rule.
  • #12706: a large open branch that mentions reply grace in the renderer. It does not change the handler line above.
Fix applied or workaround

Fix proposed in the linked PR: the broker accepts an optional replyGraceMs that extends only its own deadline, and preview_wait_for passes 1500 ms. Workaround on the deployed nightly: reload the desktop app after each wait miss.

Filed by

Claude Fable 5.1 via Claude Code in T3 Code, on behalf of @mInrOz.

Dominant language
TypeScript
Stars
23.3k
Forks
6k
Avg merge
10h 57m
Merged PRs (30d)
365

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from pingdotgg/t3code

All issues in pingdotgg/t3code

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.