Count a successful visualClick as browser progress - #214
Merged
Merged
Conversation
The tester's stall guard built its action set from ACTION_TOOLS + DELEGATED_ACTION_TOOLS + SPECIAL_CONTEXT_ACTION_TOOLS, which covers every browser-mutating tool except visualClick. So the one escape hatch the rules mandate when click() fails — "when click() fails on an element you can see, you MUST try visualClick()" — was invisible to the progress check. On a page whose control has no accessible name, every locator-based click misses by design and visualClick is the only way through. The tester used it, successfully, twice; the counter kept climbing anyway and the run went to final review before the form was ever submitted. DELEGATED_ACTION_TOOLS is read only by that check, so visualClick stays a fallback in the prompt and only starts counting as progress. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DenysKuchma
approved these changes
Sep 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What happened
Session
WeeDefeatedHarlequin414(Langfuse tracebbc695626bbc6d049f40869e15f727c2), scenario "Create a manual plan with the Run Automated as Manual option disabled…", failed after 76 seconds without ever pressing Save.The target control is
<button class="group" role="switch"><span class="flex-col"></span></button>— no accessible name at all (axe flaggedbutton-nameandaria-input-field-nameon that page). Fourclickattempts and twoxpathCheckprobes missed, correctly. The tester then did exactly what the rules atsrc/ai/tester.ts:819tell it to do and reached forvisualClick, twice, successfully — the ariaDiff proves the toggle really flipped (added: switch [checked]→removed: switch [checked]).It was cut off anyway, with
No further browser progress on unchanged page; requesting final review.Root cause
shouldStopForStalledExecution(src/ai/tester.ts:501) builds its action set fromACTION_TOOLS + DELEGATED_ACTION_TOOLS + SPECIAL_CONTEXT_ACTION_TOOLS. Against the tools actually registered insrc/ai/tools.ts(click,hover,pressKey,form,exitIframe,interact,visualClick), that set covers every browser-mutating tool exceptvisualClick— the one the rules mandate whenclickfails.Bucketing the trace's tool calls into the tester's invoke spans:
form✓form✓see✓click✗ ×3xpathCheck✗contextclick✗xpathCheck✗visualClick✓verify✗see✓visualClick✓Both iterations that drove the counter to
MAX_STALLED_ITERATIONScontained a successfulvisualClick.Fix
One line.
DELEGATED_ACTION_TOOLSis read only by that check — not by the prompt (line 527 interpolatesACTION_TOOLS) and not byactionPerformed(line 351) — sovisualClickstays a fallback in the model's eyes and only starts counting as progress. It sits besideinteractbecause both delegate the click to another model.Trade-off
visualClickreports success for any coordinate click, including one that lands on nothing, so a run clicking empty space can keep itself alive longer. The existing "don't repeat visualClick in a row" rule and state-hash dead-loop detection remain the bound.Tests
New case in
tests/unit/tester-focus-scope.test.ts→Tester stalled execution: a successfulvisualClickbetween empty iterations must reset the counter. Verified it fails onmainand passes with the fix.bun test tests/unit/— 1415 pass, 0 fail.bun test tests/integration/— 144 pass; the 3–4overlay-modal-browsertimeouts are order-dependent and reproduce onmainunchanged (that file passes 14/14 on its own).Not fixed here
Two more findings from the same trace, each deserving its own change:
Pilot Persistence Plan 2026-09-11-003, not the session name. The experience recipe's code block is a frozen data literal —I.fillField('#plan-title', 'Pilot Persistence Plan 2026-09-11-003')— and a ready-made command beats the abstract instruction attester.ts:875("include${task.sessionName}in the value"). A sibling recipe had frozen another run's session name outright. Writer issrc/ai/historian/experience.ts:339, which passescandidate.success.output.codeverbatim intowriteAction.visualClickexecutesI.clickXY(x, y), andisNonReusableCode(src/utils/step-analyzer.ts:36) deliberately drops coordinate clicks, so the resolution is never written to experience. Right call on its own terms — but the real fix is an accessible name on the control in the app under test.🤖 Generated with Claude Code