DEV Community

Cover image for Your Agent Didn't Lie to You. It Never Checked.
AutoMate AI
AutoMate AI

Posted on

Your Agent Didn't Lie to You. It Never Checked.

The Economist ran a piece this week titled "AI agents lie, cheat and steal." It hit 164 points and over 200 comments on Hacker News in a day. The comments split the way these always do: half saying the models are becoming deceptive, half saying it is overblown.

I want to offer a third reading, because I watched the exact failure happen in my own system this week, and "lying" is not what it looked like from the inside.

What actually happened

My agent was filling out a job application form. Five long free-text answers, a resume upload, a few yes/no questions. It typed everything in, checked its work, and reported back:

редактор 0: 436 символов
редактор 1: 1220 символов
редактор 2: 975 символов
редактор 3: 1834 символов
редактор 4: 258 символов
форма заполнена
Enter fullscreen mode Exit fullscreen mode

Every number is real. The text was genuinely on the screen. I could see it. A screenshot would have confirmed it.

The form received nothing.

скрытые textarea (то, что видит форма):
[{"len": 0}, {"len": 0}, {"len": 0}, {"len": 0}, {"len": 0}]
Enter fullscreen mode Exit fullscreen mode

The page used a rich-text editor — a contenteditable div — and the form itself read from a hidden <textarea> sitting next to it. The editor never synced. Not on blur, not on input, not on anything I tried. So the agent typed into a box that displayed characters beautifully and stored them nowhere.

Then it clicked Submit. The button was enabled. Nothing was disabled, nothing turned red, no error appeared anywhere on the page. The click registered. The application did not exist.

Text on screen, nothing in the field

The agent was not lying. It was answering a different question.

Here is the part I keep turning over.

The agent asked: "is the text on the screen?" Answer: yes, 1834 characters of it. That answer was true. It reported it accurately.

The question that mattered was: "does the form have the text?" Nobody asked that one. Not the agent, and — this is the uncomfortable half — not me, when I wrote the thing.

An agent cannot tell you about a state it never read. It is not withholding. There is simply nothing there. And because the observation it did make came back clean, the report reads exactly like success. Identical. There is no tone of voice in a log line.

The second bug that day was worse, and prettier.

The agent needed to answer "do you meet the timezone requirement?" with Yes. To find the right button, it walked up the DOM from each Yes/No button looking for the question text. Sounds reasonable. But go up far enough and you reach a container holding every question on the page — so the very first Yes/No pair matched every phrase you searched for.

The agent clicked Yes. On the wrong question. And then answered "do you meet the timezone requirement?" with No — while sitting in Chicago, which overlaps a full Eastern working day.

It confirmed the click. It verified the button carried the selected class. Every check passed. The answer was wrong in a way that no check I had written could distinguish from right.

If that had gone through, we would have been auto-rejected, and the log would have said everything went fine.

The search climbed too far and matched the wrong question

Why this matters more than deception

Deceptive-agent stories are compelling because they suggest intent, and intent feels like something you can negotiate with. Silent failure has no intent, and that makes it worse:

  • It scales quietly. A lying agent eventually contradicts itself. A blind agent produces consistent, confident, wrong output forever.
  • It survives your tests. I have written a test that made 8,000 calls and reported zero failures — and never once reached the bug, because my own rate limits blocked it from getting there. Green build. Untouched defect.
  • It looks like success in every dashboard you have. The click happened. The characters appeared. The status is 200. Every metric you are collecting says yes.

The Economist frames this as a trust problem between users and agents. In production it is narrower and more fixable than that: your agent is reporting on the wrong variable, and nobody noticed which one.

Zero out of eight thousand that never reached the bug

What actually catches it

Three things, in order of how much they buy you.

1. Verify state, not appearance.

Every action needs a check that reads the thing the system reads, not the thing the human sees. For a form, that means the value the form will submit. For an API call, the resource after the write, not the response body. For a file, read it back.

The rule I now hold: "it says so on screen" is not "the system accepted it." The screen is a rendering. It can be a rendering of nothing.

# not enough
editor.type(text)
assert editor.visible_text == text          # true, and meaningless

# what we do now
editor.type(text)
assert form.field_value("answer") == text   # the value that will be POSTed
Enter fullscreen mode Exit fullscreen mode

2. Make failures loud, and prove they can be.

Break it on purpose and check you get a red. If you cannot make your test fail, you have not learned anything from it passing. This is the invariant-testing habit from smart contracts, where a missed edge case is priced in dollars the same day — and it transfers directly to agents, which are also programs whose control flow is written at runtime by something you do not control.

3. Report the denominator.

Not "0 failures." Say how many times the real action executed and whether that is enough to reach the rare case. Zero failures out of 8,000 calls that never touched the code path is not evidence. It is a number that looks like evidence, which is worse than no number at all.

This is the same discipline behind the guardrail I maintain: 50,000 requests in testing, 32,981 of them deliberate attacks — path traversal, argument smuggling, tool-name spoofing. Zero got through. That claim is only worth anything because the attack count is stated. "Zero got through" on its own tells you nothing about whether anything was tried.

The uncomfortable conclusion

The failure was not in the model. No model was involved in either bug. It was ordinary code, written by me, that observed the wrong variable and reported honestly on what it saw.

That is what most "agent unreliability" turns out to be once you open it up. Not deception. Not hallucination. A confident report about a question nobody meant to ask.

Which is oddly reassuring, because it means the fix is not "wait for better models." It is the boring engineering discipline we already know how to do, applied to a place where we mostly have not been doing it: check what the system got, not what the screen shows.


I build production AI systems — agents, MCP servers, LLM pipelines — and the tests that prove they hold up. Two years, since November 2024. Not ten. Everything above is from this week's logs, and the repositories are public.

If you have an agent in production and nobody on the team can say what it is actually allowed to touch — that is the conversation I am useful for.

Top comments (0)