Engineering
June 10, 2026

The Agent Did Not Fix Itself

Eight commits. Four distinct failure modes. Every single one required a human to identify, diagnose, and resolve. The agent was not autonomous. It was not close.

Here is what the last two weeks of commit messages actually say, read literally:

a9865e0 fix: prevent raw tool output and pagination fields from leaking to user
The model was printing internal JSON to the chat. Not sometimes. Every time.
63142bc fix: cross-app auth and detection fixes across Gopher and inbox0
JWT tokens were being validated against the wrong issuer. Camera detections were returning stale data. Auth tokens were carrying wrong identifiers across app boundaries.
c89e8ef fix: inbox0 -- sql reserved keyword, llm output resilience, imap virtual folders
A SQL reserved word silently broke query construction. LLM output included characters that crashed the JSON parser. Virtual IMAP folders were being constructed with wrong path separators on non-Gmail providers.
db5845c fix: register inbox0 api_router after all routes are defined
About twenty endpoints existed in code and had never worked in production. The router was registered before the routes were defined. Two minutes to fix. Weeks of silent failure.

None of these were found by the agent. None were fixed by the agent. The agent wrote code that introduced several of them.

The Promise and the Gap

The marketing says autonomous. The demos show a cursor that types and ships. The reality is that an AI coding agent produces plausible code at speed, and a human reviews it, finds the bugs, and sends it back. The agent is fast at being wrong. The human is slow at being right. The cycle produces commits, but the commits do not happen autonomously.

What the agent does well is mechanical generation -- boilerplate, refactors across many files, test scaffolding, docstrings. It can execute a known pattern at the speed of inference. What it cannot do is verify that pattern against the running system, catch a silent failure that produces no error, or understand that a working query breaks when the account name has a trailing digit.

Failure Mode One: The Instruction Was Followed

The Gopher chat UI was dumping raw JSON tool results to the user. The system prompt said "never dump raw tool output." The model had the instruction. The model ignored it anyway.

The fix was not a better prompt. The fix was a server-side sanitizer that strips pagination metadata and formats all tool results as plain English before the model ever sees them. The instruction that the model could ignore was replaced with a runtime check that the model cannot bypass. The agent was not reined in by a better natural language constraint. It was constrained by an architectural boundary that does not depend on compliance.

The model followed the instruction when following it was the path of least resistance. When the model's own output could be fed back as input to the next turn, the instruction became negotiable. Architecture closed the gap.

Failure Mode Two: Schema Mismatch

The LLM was passing account_name: "Personal" to a tool that only accepted account_id: 2. The parameter existed in the tool description but not in the schema the validation layer actually checked. The model inferred the parameter correctly from the description, sent it in the request, and the request was silently discarded. Zero results returned. No error surfaced.

The fix required adding the parameter to the schema, updating the endpoint to accept it, and adding a fuzzy matcher so that "Personal" correctly resolves to "Personal1" in the database. Three places needed to change. The model could not have known any of them. The model had no visibility into the schema migration path because the schema error produced no observable symptom until a real user asked about their personal account.

Failure Mode Three: Silent Looping

The model was calling the same tool on every turn without synthesizing results. Three turns of the same call, each returning results, none of them ever forming a response. The model had been told to make one tool call per response. It was making one tool call per response. The instruction to synthesize after the tool result was not being applied because the model treated each turn as independent.

The fix was a loop guard: after three consecutive calls to the same tool, the server synthesizes the accumulated results into a response and returns. The model did not learn to stop looping. The server learned to stop waiting for it.

Failure Mode Four: Missing Constant

The most recent commit fixed a NameError where a constant was referenced in three places but never defined. The code compiled, the module imported, and the function ran until it hit the line that used the undefined name. Three lines of Python, zero complexity, not caught by any linting step because the name was referenced inside a function body that was not executed at import time.

The agent wrote this code. It also wrote the three references to the name. It never noticed the definition was absent.

What the Research Says

This is not a subjective observation. A growing body of empirical research confirms it. A 2026 study from Case Western Reserve analyzing 547 real-world safety failures in AI coding agents found that bug fixing and setup or configuration issues accounted for over 65% of incidents, and that agents frequently fail silently by fabricating success reports, modifying environments to mask failures, or presenting false completion claims. Nearly 60% of incidents were rated high or critical severity. The study's conclusion: existing benchmarks fail to capture these operational safety failures entirely.

Another 2026 formal verification study of 3,500 code artifacts using Z3 SMT solvers found that 55.8% of AI-generated code contained vulnerabilities, and that industry-standard static analysis tools -- Semgrep, Bandit, CodeQL, Cppcheck -- missed 97.8% of those vulnerabilities. Explicit security instructions reduced vulnerability rates by only 4 percentage points. The tools the industry relies on to catch bugs are fundamentally blind to what AI agents produce.

A third study, "Needle in the Repo," tested AI systems on maintainability across repository edits and found that only 36.2% of cases were solved correctly. More critically, 13.3% of outcomes passed functional tests but failed structural oracles -- meaning the test suite said the code was fine and the code was actually broken. The exact pattern from the ghost routes bug: green tests, broken features, silence until a human looked.

None of these failure modes can be caught by a coding agent working in isolation. An agent cannot observe that an API router was registered before its routes were defined because the code executes successfully -- it just does nothing. An agent cannot detect that a SQL reserved word is being used incorrectly in a query builder because no exception is raised until the specific account name is queried. An agent cannot know that a constant is undefined until execution reaches the line that references it. These are not coding failures. They are runtime properties of a specific deployment environment that no amount of prompt engineering, test writing, or architectural scaffolding can predict in advance.

The agent is not missing a feature. The agent is working exactly as designed -- producing plausible code quickly -- and the failures are properties of the execution context that only emerge when a human sits down with the running system and notices the endpoint returning 404.

What This Is and Is Not

This is not an argument against AI coding agents. I use them daily and they are genuinely useful for mechanical work. This is an observation about what autonomous means in practice: it does not mean the agent fixes things on its own. It means the agent produces work faster than a human would alone, and the human sits in the loop for every non-mechanical decision.

The commits above are not edge cases. They are the ordinary texture of building with an AI agent. The agent writes the first version. The human notices it broke the auth flow. The agent writes a fix. The human notices it introduced a schema mismatch. The agent writes another fix. The human notices the constant was never defined. The cycle continues until the human is satisfied and the commits are real.

The autonomous part is the typing. Everything else is human.

#AI #Engineering #Gopher #LocalAI #Security #MyOwnLifeOS #BuildInPublic
Sources: What Breaks When LLMs Code? (Case Western, 2026) · Broken by Default: Security Vulnerabilities in AI-Generated Code (2026) · Behavioral Drivers of Coding Agent Success and Failure (2026) · Needle in the Repo: Maintainability in AI-Generated Edits (2026)
Ovais Quraishi