Skip to content

fix(browser): run a command only after the Gateway confirms its ack - #34

Merged
mrgoonie merged 2 commits into
mainfrom
claude/tender-keller-w4a2cd
Oct 16, 2026
Merged

mrgoonie merged 2 commits into
mainfrom
claude/tender-keller-w4a2cd

Conversation

@mrgoonie

Copy link
Copy Markdown
Contributor

Closes #32

Problem

The command runner sent browser.command.ack without waiting for the response and started the action straight away. When an ack arrives after the Gateway's 5 s ack timeout, the Gateway has already told the agent device_unresponsive ("not run"). If the agent then retried, the action ran twice. For irreversible actions (merge, submit) that is a duplicate side effect.

Change

  • The runner waits for the Gateway's answer to the ack before it does anything.
    • Acked: the command runs once.
    • NOT_FOUND: the Gateway already finished the command. Nothing runs and no result is sent.
    • Any other ack failure (client request timeout, device_offline): nothing runs. A best-effort cancelled result is still sent, so a Gateway that did record the ack does not wait until the deadline and report outcome_unknown.
    • Cancel, Pause/Stop, grant revoke or deadline while the ack is pending: nothing runs, and the result carries the abort code.
  • Kept as before: dedup by command id, the deadline timer (now armed before the ack wait) and the existing cancellation paths.
  • A command cancelled or refused before it ran does not appear on the side-panel timeline. This is documented in the JSDoc.
  • Updated docs: connected-browser-relay-contract.md, api-contract.md, architecture.md and the CHANGELOG.

Verification

  • pnpm lint: pass.
  • pnpm typecheck: pass.
  • pnpm test: 814/814 pass.
  • pnpm build: pass.
  • New unit tests:
    • The runner does not run before the ack is answered, and runs once after it.
    • On NOT_FOUND it sends no result. On timeout, device_offline or a plain error it sends exactly one cancelled result.
    • It does not run when cancel, revoke or the deadline arrives while the ack is pending.
    • It does not run when the ack resolves and cancel arrives in the same tick.
    • A duplicate command sent while the ack is pending is ignored.
    • Session-level: the Gateway refusing the ack over the socket means nothing runs and no result is sent.
  • An isolated code review found no blocking issues. Its findings (one Medium, four Low) are fixed in 48f387d.
  • On the Gateway side, the browser-use eval harness (nextlevelbuilder/dewee#1225) models both behaviours: the old fire-and-forget ack duplicates on a slow ack, and the two-phase start does not.

🤖 Generated with Claude Code

https://claude.ai/code/session_015ovQWBCoHd61Rwg92GdXdP


Generated by Claude Code

The Gateway treats a command without a confirmed ack as not run: it fails
it with device_unresponsive after the ack timeout or device_offline on a
disconnect, and answers a late ack with NOT_FOUND. The runner sent the
ack fire-and-forget and executed at once, so an interact command could
still run after the agent was told it did not, and repeat its side
effect on retry.

The runner now awaits the ack answer before any work. A rejected ack
(NOT_FOUND, closed socket, request timeout) means the command never runs
and no result is sent. A cancel, Pause/Stop, revocation or deadline that
lands while the ack is pending stops the command before it runs and
reports that code. The seen-id dedupe, deadline timer and cancellation
semantics are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ovQWBCoHd61Rwg92GdXdP
A rejected ack other than NOT_FOUND (a local request timeout, a closed
socket) may still have been recorded by the Gateway, which would then
wait for the deadline and report outcome_unknown for a command that
never ran. The runner now sends a best-effort cancelled result in that
case; after NOT_FOUND it still sends none.

Also covers a NOT_FOUND ack at the session level and a cancel that lands
in the same tick the ack resolves, and documents that commands stopped
before they ran are not shown on the timeline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ovQWBCoHd61Rwg92GdXdP
@mrgoonie
mrgoonie merged commit 68189ae into main Oct 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(browser): run a command only after the Gateway confirms its ack

2 participants