Every engineer using an AI assistant has met the same failure: the code is fluent, idiomatic, passes a quick read — and it's wrong in a way that surfaces days later, somewhere else, under load. The industry calls it hallucinated code. It isn't rare, and it isn't going away as models get bigger; it just gets more plausible.
The four shapes hallucinated code takes
- Invented APIs. A method that doesn't exist on the SDK version you're pinned to. It compiles in the assistant's head, not in your build.
- Faked outcomes. A refund path that returns
successwithout ever calling the payment provider. Reads like defensive coding; is actually a lie. - Mocks left in the wire path. Placeholder responses and stub data that were supposed to be temporary and are now one deploy away from production.
- Claimed completion. “Done — tests pass, deployed.” Nothing was run. The assistant is pattern-matching what a finished task sounds like.
Notice what these have in common: none of them are style problems. A linter won't catch them. A second opinion from the same model usually won't either, because the reviewer inherits the blind spots of the generator.
Step 1 — separate reality checks from quality checks
The mistake most teams make is treating AI review as one pass. It needs two, in order:
- Reality gates first, and they must be deterministic. Does the claimed API exist? Does the “successful” path actually perform the side effect? Are there mocks or placeholders in production code? Is anything claimed “done” that can't be proven? These are yes/no questions — any single failure should veto the output, no averaging.
- Quality review second, only on what survives. Performance, scalability, failure modes, tech debt — scored against a published standard (ISO/IEC 25010 is the one we use), not vibes.
Step 2 — put the gate inside the assistant's loop, not after it
A gate that runs in CI catches problems after the assistant has already told you the work is finished — you pay the context-switch cost on every failure. The better place is inside the tool loop: the assistant calls the gate before presenting work, gets a verdict with specific findings, and fixes its own output while the context is still hot. The Model Context Protocol (MCP) makes this a config block rather than an integration project — the same gate then works in Claude Code, Cursor, Windsurf, or any MCP client.
Step 3 — demand verdicts with findings, not scores alone
A bare 6/10 teaches the assistant nothing. A useful gate returns the specific defect and the math: “N+1 synchronous API calls — 100 items ≈ 100 roundtrips, ~10–20 s, blocks the worker thread, trips the payment provider's rate limit.” That's a finding an assistant can actually act on — and an engineer can audit. When we run our own gate on a plausible-looking 12-line billing snippet, it comes back REJECTED — 30.8/100 with findings at that level of specificity. (The verbatim verdict is on our MCP page.)
What this looks like in practice
Once your account exists, the whole integration is one block in your MCP client config:
{
"mcpServers": {
"verificate": {
"url": "https://<gateway>/mcp",
"transport": "http",
"headers": { "Authorization": "Bearer <YOUR_TRIAL_TOKEN>" }
}
}
}From then on the assistant has four tools available — validate_ai_output, analyze_code, validate_plan and generate_code — and a standing instruction is enough to make it gate every substantive change before claiming completion.
The bar to hold
Whatever tool you use, hold it to this: deterministic reality gates with veto power, an independent review standard, findings specific enough to audit, and a place inside the assistant's loop. That combination is what turns “the AI wrote it and it looked fine” into “the work survived a veto-empowered review.”
