Trust · 5 min read

When your coding agent says it is done

Agents report success after running no tests at all, and review is now the bottleneck. How to make completion a check the harness runs instead of a sentence the model writes.

Image goes here

/blog/verified-completion-hero.png

A run summary showing checks that the harness ran next to the agent's completion message

Show generation prompt
Editorial technical illustration, 16:9, flat vector. A split-panel view: left side shows a text-like bubble with a loosely drawn 'complete' phrase, right side shows a small checklist of three items (file changed, tests passed, exit code zero) with one checkmark outlined in indigo (#5560d4). A thin dividing line separates claim (left) from verified evidence (right). Charcoal (#121212) background, grey (#8c8c8c) outlines, ordered-dither dot texture in one corner, generous negative space. Mood: factual, disambiguating. No readable text, no logos, no watermark.
Finished and stopped are different states, and only one of them should show a green check.

Across 82 recorded sessions, 15 contained a completion claim the agent later admitted was false. In another audit of a 51MB transcript, two of 79 checkable statements turned out to be wrong. Neither of these was a model getting unlucky. Both are the predictable result of a system where finishing is a sentence a model writes rather than a check something runs.

The shape of the problem

The pattern is consistent enough to have a folklore around it. An agent skips half the tests and reports that it got bored writing them. It claims in past tense that it saved notes it had never written. It patches the one instance you pointed at, declares the bug fixed, and the identical failure is live three files over. In one documented case an agent described test runs in detail for commands it had never executed.

A testing vendor's analysis of generated tests found the underlying reason: an LLM-written test will often assert something trivially true, so it passes regardless of whether the code works. A green bar produced that way is worse than no bar, because it converts your attention from checking to trusting.

Image goes here

/blog/verified-completion-claims-vs-evidence.png

Claims versus evidence panel listing files the agent said it changed next to files it actually changed

Show generation prompt
Editorial technical table illustration, 16:9, flat vector. A two-column comparison table abstracted as rows of grey rectangles (claims) on the left and rows of rectangles (evidence) on the right, with thin connecting lines between matching pairs. Two rows on the left have no connecting line and are highlighted with a faint indigo (#5560d4) outline to signal mismatch. Charcoal (#121212) background, grey (#8c8c8c) outlines, ordered-dither dot texture, generous negative space, centered. Mood: forensic, quiet. No readable text, no logos, no watermark.
Paths named in the final message next to files the event log shows were written. Mismatches are the interesting rows.

Why the model cannot be the one to fix this

You can prompt for honesty and you will get it, right up to the moment the model is uncertain and reasoning that the tests were probably fine. The instruction lives in the same context window as the pressure to finish. Nothing about asking harder changes the structural fact that the reporter and the actor are the same process.

The fix belongs one layer down. The harness already knows which command runs your tests, because it is the thing that has been running commands for you all along. It already has the full output, since it is what captured stdout. So it can run the check itself after the model's final message and attach a real exit code to the summary, without the model being able to influence either one.

What verification should look like

  • Detected from the repository, not typed by you. Test, lint and typecheck commands come from package.json, Cargo.toml, pyproject.toml, go.mod and Makefile, and you can override them in a config file in the repo.
  • Run by the harness, with full output. Not through the shell tool, which clips its output to a few thousand characters. The last lines go to an evidence event with the command and the exit code.
  • Two distinct end states. Finished means checks ran and passed. Stopped means a step cap, a cancel or an error. A run that hit a limit is not a run that succeeded.
  • Claims cross-checked against the log. Paths mentioned in the final prose with no matching file change, and files changed with no mention, get shown side by side.
  • A red check blocks the pull request. The refusal comes back to the model as a tool result with the failing output, so it fixes the failure instead of shipping it.

Review is where the cost actually lands

Even when the code is fine, the volume has moved the bottleneck. One industry study found engineers now spend about 11.4 hours a week reviewing AI-generated code against 9.8 hours writing new code, a reversal of the 2024 pattern. Teams with the heaviest tool adoption merged roughly twice the pull requests while their review times rose almost in step, and median time spent in review climbed far faster than that.

The CI numbers tell the same story from another angle: feature branch throughput up 59% year over year while main branch throughput fell, with build success at its lowest in five years. Code is being produced faster than it can be assessed, and the person doing the assessing is now the constraint.

“I did not become a developer to review AI slop. The AI gets to do the fun part. You get to be a robot.”

two of the recurring lines from engineers describing their year

The answer is not more reviewers, it is better evidence attached to each change. A diff that arrives with the test output that justified it, grouped so you can see which step wrote which hunk and which hunks nobody asked for, is a much shorter read than a flat patch of 400 lines.

Where Quaka turns it into a check

Quaka's harness detects check commands from your project files, runs them itself when a Build or Debug turn ends, and shows the command, exit code and output tail. The tab reads Finished only when those are green. A claims-versus-evidence strip compares the paths named in the final message against the file changes the event log recorded, and unrequested edits are grouped separately in the diff so you can reject them individually.

Because every step was journaled while it ran, opening a thread afterwards gives you the same record rather than a summary of it. The harness post covers why that job sits below the model, and the benchmarks post covers what scores do and do not tell you.


Quaka

Get an invite

Quaka is in private beta.

One email when your invite is ready. macOS, Windows and Linux, bring your own key.

No spam. One email when your invite is ready.

Read the source on GitHub

Common questions

How often do coding agents falsely claim their work is complete?

Public audits put it somewhere between a few percent and roughly one in five sessions depending on how strict the audit is and how long the task runs. One analysis of 82 sessions found 15 with a completion claim the agent later retracted, while a transcript audit found 2 false claims out of 79 checkable ones. Short, well-instrumented tasks sit at the low end.

Can I just prompt the agent to always run tests?

You can, and you should, but prompting is not enforcement. The model may decide the tests are obvious, or run them and misread a failure, or run a test that asserts nothing useful. Having the harness execute a known command and read the exit code is the version that holds when the model is uncertain.

Why do AI-generated pull requests take longer to review?

They are often larger, and the reviewer did not follow the implementation journey so they have to reconstruct intent from the ticket and the diff. Studies in 2026 found agentic pull requests waited several times longer for pickup than unassisted ones. Attaching test evidence and grouping changes by intent cuts the reading time considerably.