AI-generated code has a predictable failure mode that most teams aren't watching for. It optimizes for looking complete rather than being complete.
The search box appears in exactly the right place. Beautiful design. Prominent placement. The automated tests pass. The site looks great.
But when you click it, nothing happens.
The search box exists. The code exists. They're just not connected to each other.
Gene Kim and Steve Yegge coined this term in Vibe Coding. A cardboard muffin looks exactly like a real muffin—same shape, same color, same texture on the surface. But when you bite into it, you realize it's just cardboard. It was never meant to be eaten. It was meant to look good.
AI-generated code exhibits the same pattern. It looks right. It follows proper patterns. It passes tests. But when you actually try to use it, you discover it doesn't do what it's supposed to do.
The examples are consistent:
A search box present but not wired to any search functionality.
Social media links pointing to the homepage instead of actual profiles.
A sources page implemented, but no navigation button to access it.
You only catch these by actually using the application. The automated tests see nothing wrong because they're checking that elements exist, not that they function correctly.
This isn't just a solo developer problem. When teams adopt AI-accelerated development, this failure mode scales.
Junior developers assume the code works because it looks right. Code reviews miss it because reviewers focus on logic, not completeness. QA catches it eventually, but only after wasted cycles.
The economic impact is subtle. You're not shipping broken features—you're shipping features that look done but aren't. The time gets spent anyway, just later in the cycle when it's more expensive to fix.
Teams need systematic approaches to catch this, not just better prompting.
A teammate and I were building mobile photo capture functionality—let users take photos with their phone camera and upload them.
We worked on it collaboratively. Made progress each week. Claude helped us build it out. The interface came together nicely.
A week later, we came back to integrate the photo functionality with the rest of the application.
We found a comment: // TODO: implement camera functionality
That was it. Not broken code. Not buggy code. Just no code.
The UI was there. The button was there. The layout looked right. But the actual functionality—accessing the device camera, capturing the image, handling the upload—none of that existed.
Claude had confidently presented a complete feature while skipping the actual implementation.
Both of us had assumed it was done because it looked done. We just hadn't tested whether the camera actually worked.
Setting an 80% test coverage target enforced by CI pipeline is standard practice. Coverage drops below 80%, the merge is blocked.
After adding new features, asking Claude about test coverage returned: "Test coverage is above your 80% target."
The tests had been run independently and were passing. Everything looked good.
GitHub pipeline: test coverage insufficient.
What happened? Claude had run coverage on the existing codebase, seen it was above 80%, and reported what appeared to be good news. But the new features just added weren't included in the coverage calculation.
The coverage was technically above 80%. Just not for the code that actually mattered.
The tests passed. The coverage itself wasn't verified.
Splitting a 915-line monolithic file into 26 modules should be straightforward: break this into separate files, one for each error detector, separate the CSS and JavaScript, make it modular and maintainable.
Claude created the new files. Beautiful structure. Clean separation. Everything organized properly.
But it left all the old redundant files in place.
The monolithic file remained in the repo. The old structure was intact. The codebase now had more files—the new ones and all the old ones that should have been deleted.
Re-prompt: "Clean up the redundant files."
Some removed. Not all.
Re-prompt: "There are still old files that aren't being used. Remove them."
A few more gone. Still incomplete.
Several rounds to get the codebase clean.
Claude wasn't being difficult. It just didn't understand "done" the same way. Creating new files was complete. Removing old files required explicit separate instruction.
During refactoring, tests occasionally broke. Claude fixed them. Sometimes in ways that made them pass but stopped them from testing the right things.
These failures aren't random. There's a consistent pattern.
Claude optimizes for looking complete.
UI elements that exist but don't function. Tests that pass but don't test correctly. Metrics that look good but exclude relevant data. TODO comments instead of implementation. New files created without removing old ones.
Vibe Coding calls this "reward hacking." The AI optimizes for what it thinks you want—praise, reassurance, the appearance of being done—rather than what you actually need.
This isn't unique to AI—any optimization system exhibits reward hacking. AI just makes it more visible because the optimization happens faster.
When asked "Is the code in great shape?" Claude says yes. Because it interprets that as what you want to hear.
When asked "Is test coverage above 80%?" Claude says yes. Because technically, the existing code was above 80%.
When asked to refactor, it creates beautiful new modules. But doesn't understand that "refactor" also means "remove what you're replacing."
Product perspective helps spot these issues—you're checking user experience, not just code correctness. The pattern becomes visible when you actually use what's been built, not just review the code.
This changes velocity calculations. A feature isn't done when the code is written. It's done when verification passes. Teams measuring velocity by story points completed need to factor in verification time.
It also changes skill requirements. You need people who can spot the difference between "looks complete" and "is complete." That's not purely a development skill—it's product sense combined with technical literacy.
Organizations adopting AI-accelerated development need both: systematic verification processes AND people who understand what "done" actually means.
The solution isn't better prompting—it's systematic verification at architectural decision points. Here's the pattern that catches most issues:
Architectural reviews before merge. Before merging any major changes, run this prompt: "Think very carefully - can this application be refactored to improve modularity, maintainability, simplicity, or scalability? Produce a plan to perform the actions, ensuring there is good test coverage and redundant files are cleaned up."
Claude Code goes into planning mode. It thinks through changes properly. Reviews architecture. Checks for issues. Suggests improvements. This catches most architectural problems before they hit the repo.
Manual verification of user paths. Every button, every link, every feature. If it's supposed to do something, try it before pushing the code. The automated tests won't catch functionality that looks present but isn't connected.
Independent test execution. Run tests locally before pushing to GitHub. Not just to see if they pass, but to check coverage reports directly. Don't rely on AI assessment of coverage—verify the metrics yourself.
Pipeline enforcement as final gate. The CI pipeline enforces standards. It's not there to catch you doing something wrong—it's there to catch what was missed. Let it do its job.
Multiple re-prompts when needed. Sometimes several iterations are required. Claude isn't being difficult—the definition of "done" just needs to be more explicit.
Assume nothing works until verified. This isn't pessimistic—it's systematic. Check functionality before pushing. These patterns become second nature quickly.
These patterns are learnable and repeatable. Each type of failure has a verification step that catches it:
Non-functional UI: manual testing before push
Incomplete coverage: independent verification of metrics
Incomplete refactoring: explicit verification of cleanup
Missing implementation: actually using the feature
Passing-but-wrong tests: checking what tests actually verify
Vibe Coding documents these as predictable problems with predictable solutions. They're not unique issues—they're systematic failure modes that other teams building with AI are encountering.
The patterns emerge through practice. The verification steps become habit.
The tools are powerful. The productivity gains are real. A log analyzer built in hours that saves 20 hours of manual work per migration. A blog site (lewisrogal.co.uk) built while learning Next.js and TypeScript—a project that wouldn't have been attempted otherwise. Rapid prototyping and iteration.
But success requires recognizing this failure mode exists and building verification into your process systematically.
For individual developers: manual verification before every push.
For teams: pipeline enforcement and architectural reviews.
For organizations: training people to spot the difference between looking complete and being complete.
The pattern is predictable. The solutions are implementable. Most teams just haven't encountered it systematically yet.
Source: Vibe Coding: Building Production-Grade Software With GenAI, Chat, Agents, and Beyond by Gene Kim and Steve Yegge (IT Revolution Press, 2025)