You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: preview_wait_for evicts healthy hosts when operation and broker deadlines match #12407
If the agent omits timeoutMs, both sides default to 15000.
The broker then waits exactly that long and disconnects the host if no reply arrives:
constresult=yield*Deferred.await(deferred).pipe(Effect.timeoutOption(timeoutMs));returnyield*Option.match(result,{onNone: ()=>Effect.gen(function*(){// An unanswered request invalidates this connection. Do not replay// actions: the client may have applied them before becoming unreachable.yield*disconnect(connection.clientId,connection.queue);returnyield*newPreviewAutomationTimeoutError(requestContext);
Desktop waitFor also uses the full budget and can overshoot it. The loop is while (now <= deadline) and still sleep(100) after the last miss. So on a miss, the host reply is at or after the broker deadline. The broker timeout wins, the connection is closed, and the assignment is dropped. A late PreviewAutomationTimeoutError cannot restore it (#11381 explicitly ignores late traffic from the evicted connection).
This is the opposite of the contract #11381 added: “A host that replies with an operation-level timeout remains available.”PreviewAutomationBroker.test.ts covers that only when the host replies immediately. It does not cover equal operation/broker deadlines.
Overlay readiness already reserves slack (PREVIEW_HOST_RESPONSE_MARGIN_MS = 1500) so the host can answer before the broker fires. waitFor never uses that budget.
User-visible effect: one unmatched wait evicts a live desktop runtime. The next preview_* call loses the pinned tab, failovers to another host, or returns PreviewAutomationNoAvailableHostError.
Related but distinct: #12146 / PR #12343 (reconnect after eviction — does not prevent this), #12273 / PR #12279 (optional 500ms metadata non-evict — leaves primary deadlines unchanged).
Suggested fix
Keep #11381 eviction for truly unanswered hosts. Make an operation-level wait miss report before the broker deadline:
Cap desktop waitFor (and any other full-budget wait) with the existing host-response margin, or make the broker deadline strictly larger than the operation timeout.
Stop the wait loop on now < deadline (don’t sleep past it).
Add a broker test where the host replies with PreviewAutomationTimeoutError at timeoutMs (test clock). The host must stay assigned; a later status must still route there.
Do not special-case “never evict waitFor” — a frozen host should still be released.
Activity
juliusmarminge commentedon Sep 18, 2026
Triage
Confirmed bug on current
main. A healthy desktop host that finishes an honestpreview_wait_formiss is treated as unanswered and evicted.What happens
preview_wait_forforwards the sametimeoutMsas both the MCP/broker deadline and the host operation timeout:If the agent omits
timeoutMs, both sides default to15000.The broker then waits exactly that long and disconnects the host if no reply arrives:
Desktop
waitForalso uses the full budget and can overshoot it. The loop iswhile (now <= deadline)and stillsleep(100)after the last miss. So on a miss, the host reply is at or after the broker deadline. The broker timeout wins, the connection is closed, and the assignment is dropped. A latePreviewAutomationTimeoutErrorcannot restore it (#11381 explicitly ignores late traffic from the evicted connection).This is the opposite of the contract #11381 added: “A host that replies with an operation-level timeout remains available.”
PreviewAutomationBroker.test.tscovers that only when the host replies immediately. It does not cover equal operation/broker deadlines.Overlay readiness already reserves slack (
PREVIEW_HOST_RESPONSE_MARGIN_MS = 1500) so the host can answer before the broker fires.waitFornever uses that budget.User-visible effect: one unmatched wait evicts a live desktop runtime. The next
preview_*call loses the pinned tab, failovers to another host, or returnsPreviewAutomationNoAvailableHostError.Related but distinct: #12146 / PR #12343 (reconnect after eviction — does not prevent this), #12273 / PR #12279 (optional 500ms metadata non-evict — leaves primary deadlines unchanged).
Suggested fix
Keep #11381 eviction for truly unanswered hosts. Make an operation-level wait miss report before the broker deadline:
waitFor(and any other full-budget wait) with the existing host-response margin, or make the broker deadline strictly larger than the operation timeout.now < deadline(don’t sleep past it).PreviewAutomationTimeoutErrorattimeoutMs(test clock). The host must stay assigned; a laterstatusmust still route there.Do not special-case “never evict
waitFor” — a frozen host should still be released.Related
preview_navigatetimeout misreport. Different bug; leave it separate.Labels:
bug,accepted,via-triage