Your vibe coded app worked in the demo and broke in production

A few weeks ago, before shipping a chunk of work I had vibe coded, I pointed an independent audit agent at it. Not the tool that wrote the code. A different one, cold, told only to go looking for what breaks. The build was green. Every test passed. The demo was clean. The audit came back with two bugs anyway, and neither of them threw an error. They were just quietly wrong, sitting in the exact place a happy-path test never looks.

If your vibe coded app worked in the demo and then broke the moment a real user touched it, the cause is almost always the same, and it rarely has much to do with the AI writing bad code. The generator optimized the happy path and never wrote the failure surface: the empty input, the timeout, the blank field, the page that checks you are logged in but never checks whether you are allowed. Production is the failure surface. The demo is the happy path. The fix is to spec the failure surface before the build and run an independent audit pass by an agent that did not write the code, because the bugs that reach production are the ones that do not throw.

why does an AI app pass every test and still break in production?

Because the test suite and the code were written by the same optimizer, aiming at the same target. When you ask an AI to build a login form, it builds a login form that logs a valid user in, and then it writes tests that log a valid user in. Both halves are pointed at the happy path. The suite goes green because it is measuring the surface the generator was already good at. The failure surface, the wrong password five times in a row, the email field left blank, the session that expired mid-request, is not in the code and therefore not in the tests either. Nothing is red because nothing is looking.

This is why "it passes tests" is a claim about coverage, not correctness. A green suite tells you the code does what the tests check. It says nothing about the cases the tests never imagined, and those are precisely the cases a real user will find in the first hour. Passing tests measured the wrong surface. It bites vibe coding especially hard, because the whole appeal is generating the working path fast, and the failure surface is exactly the part nobody thought to ask for. The trap is structural, not a mistake you can prompt your way out of after the fact.

what is the failure surface, and how do you write it down first?

The failure surface is the set of everything that can go wrong that the happy path ignores. Empty and malformed inputs. Timeouts and half-finished requests. Concurrent edits. Authentication without authorization, where the app confirms who you are and forgets to check what you are allowed to touch. These are not edge cases. They are the normal weather of production, and an AI generator treats them as afterthoughts because you did not ask for them by name.

So ask for them by name, before the build. This is failure-surface-first, and it is a spec move, not a testing move. Before generating the feature, write down what the feature must do when the input is empty, when the call times out, when the user is authenticated but unauthorized, when two things happen at once. Now those cases are requirements the generator has to satisfy, not gaps it gets to skip. You are not testing the failure surface into existence after the code is written. You are specifying it into the code from the start, which is the only place it reliably survives. A vibe coder who writes the failure surface as its own set of requirements ships an app that bends where a happy-path build snaps.

why a different agent has to run the audit

Here is the part that caught the two silent bugs. The audit pass has to be run by an agent that did not write the code, because the tool that wrote a blind spot is the last thing that can see it. The generator already believes the failure surface is handled, in the same way it believed the tests were sufficient. Asking it to review its own work gets you a confident second pass over the same happy path. You need a cold reader with a different instruction: not "does this work," but "where does this break."

The two bugs it found were both on the failure surface and neither one threw. The first was an empty field that produced a valid-looking wrong result: no crash, no error, just a confidently incorrect answer the test suite approved, because the suite only ever passed a filled-in field. The second was a page gated on authentication where the data fetch behind it had no authorization check at all, so any logged-in user could pull data that was not theirs. Both would have sailed through the demo. Both would have surfaced in production as either a support ticket or a breach. An independent audit found them in ten minutes because it was looking at the surface the builder was structurally unable to see.

The failure mode to avoid, once something does break in production, is re-prompting the crash back into the tool that wrote it. You paste the error, it patches the symptom, and because it still cannot see the failure surface, the patch grows the blast radius instead of shrinking it. That is how a vibe coded app that broke in one place ends up broken in three. The move is not a faster patch loop. It is a spec of the failure surface up front and a cold audit before you ship.

questions that keep coming up

Do I have to rebuild my app from scratch to fix this? Usually not. Most production breaks in vibe coded apps are concentrated on a few unguarded inputs and one or two missing authorization checks. A failure-surface audit finds them without touching the parts that already work.

Can't I just add more tests? More happy-path tests measure more of the same surface. What you need is tests aimed at the failure surface, and the fastest way to know which ones to write is a cold audit pass that tells you where the code actually bends.

Why not have the AI review its own code? Because it grades its own blind spot as passing. The value of the audit comes entirely from the reviewer not being the author. Different agent, different instruction, or the pass is theater.

If you inherited or built a vibe coded app that worked in the demo and is now breaking on real users, and you want someone to think through the failure surface with you before it turns into a rebuild, /work-with-us. A lot of vibe coding goes sideways right here, at the surface the generator never wrote and the happy-path suite never checked, and half of good AI orchestration is refusing to trust a green build you have not audited from the outside. Speccing the failure surface first is cheap. Finding it in production is not.

The reason this works is not clever. The demo is the happy path, production is the failure surface, and they are different surfaces. Name the failure surface before the build, audit it with an agent that did not write the code, and the bugs that do not throw stop being the ones your users find first.

// part of the ai project rescue topic

// grab the free starter kit that makes your AI stop forgetting and stop guessing: get it →

// building with AI? the field manual has the structured lessons.

// hitting this on a real build? this is what I fix →