Two numbers tell the whole story of 2026. AI coding tools are now used by around 90% of developers at work, and only 29% of developers trust the code those tools produce — down from roughly 40% two years earlier. Adoption went nearly universal. Trust went the other way.
Nobody is going to close that gap by using AI less, because nobody is willing to give back the leverage. So it sits there as a standing liability: teams ship code they don't fully believe in, faster than they've ever shipped anything, and the belief problem only compounds as the volume climbs. The real question is what you put underneath all that code so low trust stops being dangerous.
The trust gap is earned, not irrational
Developer skepticism here is well-calibrated. When CodeRabbit analyzed 470 pull requests, AI-authored code carried 1.7x more issues than human-written equivalents, with logic and correctness problems running about 75% higher. Roughly 45% of AI-generated code fails OWASP Top-10 security benchmarks. And the review habits that would catch this are eroding under the volume: fewer than half of developers consistently review AI code before committing it.
Bad AI code is the least of it. The thing that actually bites is the combination: more code, produced faster, reviewed less, trusted less, and shipped anyway. The reflex answer, reading every diff more carefully, runs straight into the reason the diffs exist in the first place: you adopted the tools precisely to stop writing every line by hand, so putting a human back in front of the output just hands back the leverage you paid for. Diff review doesn't scale at the rate generation does, and pretending it will is how the 45% gets through.
Karpathy's reframe: keep the leverage, add the scrutiny
Andrej Karpathy named the escape hatch in 2026 when he drew a line between vibe coding and agentic engineering. Vibe coding, in his framing, raises the floor: you describe what you want, accept what the agent hands back, and move on. It's fast and it has no quality bar. Agentic engineering keeps the speed but treats the model as what it is — a powerful, fallible collaborator that is "wrong in surprising ways" — and wraps it in discipline: spec design, review, and, critically, eval design: building feedback loops with verifiable signals.
That last one carries the weight. Scaling scrutiny doesn't mean reading more code; it means verifying more behavior. A feedback loop built on a verifiable signal doesn't care whether a human or a model wrote the line that broke. It tells you the same thing every time, mechanically: whether the app still does what it's supposed to do. That signal keeps working when the diff is 40 lines or 4,000, whether you read it or not.
For end-to-end products, the verifiable signal has a name that predates the AI era: a regression suite. You describe what the app must do once, in plain language, and a test holds that line every time the code changes afterward. The behavior is pinned. The implementation underneath is free to churn.
Why behavior verification is the right layer
A diff review can tell you the code looks correct. It cannot tell you the app still works, and that second thing is the only one your users ever experience.
Consider a checkout flow. An agent refactors the payment handler across a dozen files. You can read all twelve diffs and convince yourself they look reasonable — the trust gap statistics suggest you'll be wrong more often than you'd like. Or you can have one test that says: a user with items in their cart can enter card details, submit, and land on an order-confirmation page. If the refactor broke checkout, the test goes red regardless of how clean the diffs looked. If it didn't, you're free to keep moving. The behavioral assertion is doing work that twelve careful reads can't guarantee.
This is exactly the trade the economics of test maintenance push you toward. A suite anchored to observable behavior, meaning what the user sees rather than how the code happens to be structured, survives the constant internal churn that AI-assisted development throws at it. Anchor those same assertions to implementation details instead and the suite turns into noise. Where you point the assertions decides which of those you get, and it's the same line that separates a test catching real regressions from one that just flakes and trains you to hit re-run.
The description is the artifact you actually maintain
This has to stay practical, especially for the growing number of non-traditional builders shipping real products with agents. If the verification layer made you hand-write Playwright for every flow, you'd have just moved the bottleneck around: vibe coding the app, then painstakingly hand-coding the tests that check it.
The move that keeps the leverage intact is to describe the behavior in plain language and let generation produce the test. You write: "A signed-in user can add a product to the cart and complete checkout with a saved card." A system generates the Playwright, runs it against your real URL in an isolated session, and only keeps it if it actually passes a real run. That last condition is the non-negotiable part. A test that references a button that isn't there gets caught and rewritten before you see it, not merged on the strength of looking plausible.
That inverts the artifact you maintain. Instead of babysitting brittle selector code, you maintain a plain-language description of intended behavior, the thing you actually understand and the thing that should only change when the product itself is meant to change. Writing that description well becomes the skill, the same way Karpathy puts spec design at the center of agentic engineering. The human checkpoint moves up to intent, where a human belongs, and the machine takes over the tedious but essential job of running the thing until it genuinely passes.
None of this requires slowing down or trusting your agents less than you already do. The point is to aim that distrust somewhere useful. You keep vibing on the implementation, and a behavioral suite you described once holds the line underneath, going red the moment the app stops doing what you said it must. That's the safety net that lets you keep the speed without shipping the 45%.
The takeaway
Vibe coding won, and reading more diffs won't close the trust gap it opened, because diff review is the exact bottleneck the tools were adopted to remove. What closes it is moving scrutiny from code to behavior: describe what the app must do once, then let a regression suite that has to pass a real run enforce it on every change that follows. Describe the flow, watch it fail the second a button goes missing, watch it stay green while the code underneath churns.
Want to see it in practice? Describe your first flow in plain language and watch it become a verified test in Getting started with your first test, or get early access to try it against your own app.