Skip to content

Add the computer and approvals journeys to the end-to-end suite - #1529

Merged
davidmckayv merged 3 commits into
mainfrom
e2e/computer-approvals
Nov 12, 2026
Merged

davidmckayv merged 3 commits into
mainfrom
e2e/computer-approvals

Conversation

@davidmckayv

Copy link
Copy Markdown
Contributor

What

Slice 3 of the end-to-end suite: the Bot's computer and approvals, as nine journeys on the harness from #1521. bun run test:e2e runs them after the core loop, in strict replay over aimock, against the real local stack.

Journeys

  • computer-browse: a Bot opens a page and answers from it. The Computer opens on its live screen (tabs Screen and Terminal, " has control", Take control), Activity lists "Opened page" with the address, the page title and the time, the conversation folds the browsing into one line that opens to its steps, and Activity still lists the step after a reload.
  • computer-take-control: full-size screen while the Bot holds the wheel (address shown, Back, Forward and Reload disabled, "Take control to record."). Take control, go somewhere from the address bar, Back, Forward, Reload, New tab (the address takes the keyboard), browse in it, close it, Clear browser data asks and Cancel keeps it, Hand back. Settings, Computer lists the Bot's browser: Stop browser, then Reset asks and removes it.
  • computer-terminal: a Bot runs a command; Activity shows it with its output and time; the Terminal tab shows the live shell; the person takes control of the terminal, types a command, sees its output, and hands back.
  • computer-form: one message has a Bot fill in a form. The model sends three fields and a checkbox in one step (four tool calls in one response), then submits. Every action runs, the site receives exactly the values asked for, and Activity lists every step with its time, none failed.
  • computer-sign-in: a Bot reaches a password field and the step is handed to the person ("I did it myself" and "Don't do it", no standing answer). The person takes control, types the password into the Bot's screen, hands back, answers "I did it myself"; the Bot carries on from the signed-in page.
  • approvals-allow-once: paying asks first ("Paying, buying or moving money asks you first.", all four answers offered, nothing bought yet). Allow once places the order; the next order asks again, and the same request waits on the Bots page under Needs you (Deny, Allow, and the standing answers in its menu); Deny there places nothing and the Bot says so.
  • approvals-this-conversation: Allow for this conversation places the order; the second order goes through with no card; the banner reads "Paying on host.docker.internal:46600 is allowed in this conversation."; Turn off removes it and the next order asks again.
  • approvals-always: Always allow here places the order; in a new conversation the Bot pays without asking; the rule is on the Bot's Approvals page ("Take action without asking") and Remove takes it away.
  • approvals-settings: Extra vigilant and Auto-review on and off, Commands on your computer, each kept across a reload; a rule for every Bot added, its behaviour changed (kept across a reload), removed; Cancel leaves nothing; the old /approvals address opens these settings.

The reply after every approval and every Bot answer is checked word for word on screen, once, against the text the run streamed (the conversation's own events).

How they stay deterministic

  • The run's own website (e2e/site/site.ts), served on 127.0.0.1:46600 while a journey runs and reached by the Bot's browser at http://host.docker.internal:46600. No third-party site. It counts orders, forms and sign-ins, so a journey checks what the Bot did, not only what it said (Allow once: one order; Deny: none). The port is fixed whatever E2E_PORT_OFFSET says, because the address is in the person's words and so in every fixture.
  • A Bot of its own per journey (makeBot, a fixture), made through the API as setup and deleted when the journey ends, pass or fail. A Bot's browser numbers its snapshots and a recorded click carries the number; a fresh Bot starts at the beginning whichever journeys ran first. Rules and conversation answers stay with that Bot, and later journeys see only the Bots they expect.
  • A reply is awaited by what it says and read twice the same before it is compared (a turn on the computer is several runs; see the events finding below). Each conversation is waited on until it has its name, so the naming call is recorded with the journey that caused it.

Shared files changed

  • e2e/harness/config.ts: E2E_PORT_OFFSET, the same change as the Bots and conversations slice's (plus the Composio stub's port, which main added since), so two slices' runs on one machine get their own ports and compose project.
  • e2e/journeys/settings.journey.ts (apps, routines and settings, on main): its Activity search for the core loop's key assumed the key's event is among the newest 50. With these journeys before it, a Bot's browsing pushes it further back, so the step now presses Show older events until the event is loaded, as a person would.
  • README: a section on these journeys.

Run on a Mac

  • Rebased on main (with the apps, routines and settings journeys). Two full strict replays back to back of the whole suite (stack, core loop, these nine, and the apps, routines and settings journeys): 31 of 31 passed both times, the two that slice marks as known failures failing as marked; grep -c -E "NO FIXTURE MATCH|STRICT:" printed 0 both times.
  • Fixtures recorded from the real product with bun run test:e2e:record; the core loop's fixtures are unchanged.
  • Format, lint and typecheck clean.
  • Every screenshot read.

Product bugs found (not fixed here)

  1. Activity names a declined or handed-over click by its ref. Ask a Bot to buy, Deny the card (or answer "I did it myself" on a password field): Activity reads "Declined f2e13" or "Clicked on page e14 · You did it yourself." Expected the control's label ("Place order", "Password"), as the allowed click's row shows.

  2. Steps after an approval have no time in Activity. Allow (or "I did it myself") a held step: the steps the Bot then takes ("Read page", "Inspected page") are listed without a time, while every other row has one. Expected a time, as the page watched them happen.

  3. The Reset dialog's title changes while it closes. Settings, Computer, a Bot's Reset, Reset it: as the dialog fades out it reads "Reset the computer?" (the wording for resetting every Bot) instead of "Reset 's browser?".

  4. A black band under the Bot's page after closing a tab. Full-size screen, take control, New tab, browse, close it: the remaining tab's page no longer fills the screen and a black strip shows under it, still there after Hand back. Seen in every run.

  5. A reply's stored events can briefly lack a piece of it (needs triage). Read the moment the run after an approval had finished, the conversation's events gave "Your Giant sunflower seeds order is confFH-2044." while the screen showed the whole sentence; read again a moment later, whole. A reload in that window would draw the cut reply. Seen once.

  6. The masked secret box can't be reached for a password (needs triage). computer_request_secret tells the Bot to focus the field with computer_click first, and a click on a password field is always handed to the person. In the recording the Bot did exactly that, and got the hand-off card.

Left out, and why

  • Recording a task in the Bot's browser: it records to Learning in Intelligence, which the run does not mock. The Record panel is checked (it waits for the person to take control).

Nine journeys over the Bot's computer and approvals, in strict replay:
browsing with the live screen and Activity, taking the browser and the
terminal over and handing them back, a form filled in one step, a
password handed to the person, and Allow once, Allow for this
conversation, Always allow here, Deny and the Approvals settings.

The Bots browse a website the run serves itself (e2e/site), which counts
the orders, forms and sign-ins it receives, so each journey checks what
the Bot did as well as what it said. Each journey makes its own Bot and
deletes it after.

E2E_PORT_OFFSET lets a second run on the same machine use its own ports.
… before searching

The allow-once journey answers its second order where it also waits, on
the Bots page under Needs you, and checks the row's standing answers in
its menu.

The settings journey's Activity search looked for the core loop's key
among the newest 50 events. With the computer journeys before it, a
Bot's browsing pushes that event further back, so it presses Show older
events until the event is loaded.
@davidmckayv
davidmckayv merged commit bb2bc02 into main Nov 12, 2026
24 checks passed
@davidmckayv
davidmckayv deleted the e2e/computer-approvals branch November 12, 2026 22:55
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.

1 participant