That Friday, an agent told us a UI bug was fixed when all it had done was edit some JavaScript and reload nothing. The most valuable line we have ever added to an AI agent’s ruleset is a refusal, and it came out of that moment: do not assume the fix works without re-testing it in the browser.
If you give a coding agent browser tools, this rule earns its keep because it makes the completion claim match an observed result.
The setup
We maintain a live SaaS platform built as a legacy application on server-side JScript. You find functions in it by line number, because the core edit file runs to tens of thousands of lines and the main template file is not far behind. There is no build step, no module system, no React, no JSON API. State gets to the browser by string-concatenating JSON.stringify() into an inline <script> tag. It pays the bills, and it is exactly the kind of codebase where a one-character change in the wrong scope silently corrupts a save.
When we fix UI bugs in this thing, we do it by actually looking at the page. We run Cursor with the chrome-devtools MCP server. We tell the agent “open this in Chrome DevTools,” and it drives a real browser: navigate to the admin page, take a snapshot, inspect the live DOM, see what is actually rendered. That part works well. The agent sees the bug the same way we do.
The trouble starts after it writes the fix.
What the agent did
It edited the code and announced success. In effect it said the code changed and should work now. That is the same category of mistake as pushing a branch you never ran. The claim “the code was written” got dressed up as the claim “the behavior was confirmed,” and those are different claims.
On a normal day this is annoying. On the legacy platform it is dangerous, because the bugs we were fixing that Friday were the silent kind. We were working through a feature where an account admin could drill into a child record from a dropdown. The moment they did, saves started writing to the parent account instead of the record they were looking at. Nothing threw. The save succeeded, against the wrong row. You only notice when the data shows up under the wrong record, or never shows up where you are looking.
That is the worst category of bug to “fix” without verifying. An agent that edits the code, reasons its way to “this should be correct now,” and reports done has told you nothing. The save still succeeds. It might still be saving to the wrong account. The only way to know is to reload the page, redo the action, and check the result in the running app. Reasoning does not substitute for that. Neither does a green compile, because there is no compile.
The rule
So we committed a rule. It lives at .cursor/rules/chrome-devtools-mcp.mdc, and the part that matters is a section the file calls “Testing mode.” If the user starts by looking at or testing in Chrome DevTools, that puts the session in testing mode, so after making the fix, the agent verifies it the same way. Reload the page, take a snapshot, confirm the element is visible, has no wrong class, lays out correctly, whatever the original symptom was. The verbatim line we care about most: “Do not assume the fix works without re-testing in the browser.”
That is the whole trick. The rule forbids the agent from merging the two claims. If you found the bug by looking, you confirm the fix by looking. Same loop, closed.
It works because it goes after the failure mode directly. A detailed instruction about DOM reasoning still would not establish that the rendered behavior changed. The verify-loop rule redefines “done” as an observation, not an inference.
Pin the footguns in the same file
The rule does a second thing that matters almost as much. It pins down the MCP tool gotchas that the agent gets wrong on the first try, every time.
Two examples from our file. The wait_for tool takes a text string to wait for, so passing it a number of seconds gets you nothing useful. If you want a time limit, that goes in a separate timeout argument in milliseconds. An agent that does not know this will pass a duration where the text goes, get no result, and then reason on top of a broken wait. And there is no separate reload tool. You reload by calling navigate_page with type: "reload". An agent that goes hunting for a reload tool burns a turn failing before it figures that out.
These are the two things that go wrong the first time, so we wrote them down next to the rule that makes the agent reload in the first place. The rule says “reload and re-snapshot to verify,” and right below it the file says here is precisely how you reload with this MCP, and here is the argument you will get wrong. Putting the verify requirement and the verify mechanics in the same file is the difference between a rule that fires and a rule that fails halfway and gets abandoned.
That pattern is worth stealing. When you add a behavioral rule that depends on a specific tool, document the tool’s footguns inline. A rule the agent cannot mechanically execute is worse than no rule, because it produces a confident wrong answer where a plain statement that it could not verify would have served.
Why this reaches past our stack
You might think this is a legacy-application-with-no-tests problem, and that a real test suite makes it moot. It does not entirely. A test suite confirms the assertions you wrote, while a visual or interaction check can catch a rendered page that is still wrong, invisible, or awkward to use. For UI work, “the test is green” and “the page is correct” are different claims. Browser verification is one useful check for the second claim, alongside appropriate automated tests.
The deeper point is how agents fail. They fail the way an eager junior fails, by reporting the action they took when you wanted the outcome they observed. “The code was changed” is an action. “The page was reloaded and the save now writes to the right account” is an outcome. Left to its defaults, an agent hands you the action and lets you assume the outcome. One line in the ruleset takes that swap away from it.
When an agent reports a UI fix as done, ask whether it reloaded the page and observed the result, or only edited code. Write that requirement into its ruleset, and put the details of the tools it needs for the check in the same file so the rule can actually be carried out.