A study by METR published earlier this year found that experienced developers working on their own mature codebases were 19% slower when using AI coding tools. Not faster. Slower. What makes it worse is that those same developers estimated they were working 20% faster.
That is a 39-point gap between perception and reality. The developers felt the flow, felt the productivity, watched lines of code appear faster than they could type, and concluded they were crushing it. The clock said otherwise.
This is what I am calling the vibe ceiling. Every developer who uses AI tools has one. It is the point where trusting the AI output starts costing more than reviewing it, where the confidence you feel outpaces the quality you are actually shipping. The ceiling is not fixed. It moves depending on what kind of code you are writing, how familiar the codebase is, and how much it costs if something goes silently wrong.
The problem is that the vibe makes you feel like the ceiling is higher than it is.
I have written before about vibe coding and the ways it creates new classes of problems. I have also written about spec-driven development as a methodology that keeps you on the right side of those problems. But neither of those pieces answers the question that comes up most often in practice: in this specific moment, looking at this specific diff, do I ship it, review it carefully, or rewrite it myself?
That is what this framework is for.
Why Experienced Developers Get Hit Hardest
The METR finding is counterintuitive. You would expect that developers with more context about their codebase would get more out of AI tools, not less. More context means better prompts, better calibration of the output, better judgment about what to accept.
The reason it goes the other way is exactly that familiarity. On your own mature codebase, you have spent years building mental models of how things work. When AI generates code that fits the surface pattern of your system but misses a deep constraint, your familiarity makes the output look right. The code is structurally plausible. It matches the patterns you recognize. So you accept it.
A developer working on an unfamiliar codebase with AI assistance is more suspicious by default. They review more carefully because they know they might be missing something. The experienced developer, who should know better, feels confident and skips the review.
Greenfield work is different. On a new project where patterns have not solidified and constraints are minimal, experienced developers using AI tools do accelerate significantly. The METR effect is specifically about mature codebases where the AI does not know what you know.
The framework I am about to describe accounts for this. It is calibrated differently for greenfield versus mature systems because the risk profile is genuinely different.
The Three Questions That Matter
Before shipping any AI-generated code, three questions cut through the vibe and give you real information about the actual risk.
Question one: What is the blast radius if this code silently does the wrong thing?
“Silently” is the important word. Code that crashes loudly is fine. A test catches it, the error surfaces immediately, you fix it. Code that does something subtly wrong and keeps running is a different category of problem.
If the blast radius is one user’s UI rendering slightly wrong, that is low risk. If the blast radius is corrupted payment records for every user who transacts in the next six hours before anyone notices, that is not something you accept on vibes.
Estimate the blast radius before you merge. If the scope is narrow and recovery is fast, you can move quickly. If the scope is broad or recovery is slow, you stop and read every line.
Question two: Can you roll this back in under ten minutes if it is wrong?
This is the reversibility test. Feature flags, database migrations, third-party integration configurations, and anything that touches external state can be very hard to reverse cleanly. A UI change is easy. A data migration that ran in production is not.
If the answer is yes, you can afford to ship and watch. If the answer is no, you need higher confidence before you merge.
Question three: Would you accept this on a code review from a junior developer?
This reframes how you look at the diff. You are not looking at “AI output that I generated.” You are looking at code that landed in your review queue from someone who might be sharp but does not know your system as well as you do. Would you approve it as-is? Would you ask for changes? Would you send it back entirely?
The vibe makes AI output feel like your own work. It is not your own work. Reviewing it with the same critical eye you would bring to any external contribution is not paranoia. It is the right behavior.
The Code-Type Classification System
Beyond the three questions, different categories of code have different default trust levels. Here is how I classify them.
Green: Ship with a light scan
These code types are low-risk enough that a quick read is sufficient before merging:
- UI components and styling that do not interact with business logic
- Boilerplate: file structure, configuration, repetitive setup
- CRUD scaffolding that follows patterns already proven in your codebase
- Test generation for pure functions with clear inputs and outputs
- Documentation, comments, README updates
- Type definition files that mirror existing patterns
- Build configuration changes with narrow scope
For green code, you still read the diff. You just do not need to trace every code path. You are checking for obvious problems, not verifying every assumption.
Yellow: Review the diff carefully before merging
These code types are where the interesting judgment calls live:
- Data transformations that change the shape of data flowing through your system
- Third-party API integrations where the external service has its own quirks
- Anything that writes to or reads from external state: databases, caches, message queues
- Async code, especially anything with error handling and retry logic
- State management logic, especially in complex client-side applications
- Anything that touches configuration values that behave differently across environments
For yellow code, you read every function carefully. You check that error cases are handled. You verify that the data flow makes sense. You do not need to rewrite it, but you need to understand it before it ships.
Red: Read every line or write it yourself
These code types have high enough risk that accepting AI output on trust is not appropriate:
- Authentication and authorization logic
- Payment processing or any financial calculation
- Cryptography: key generation, token signing, encryption, hashing
- Anything that touches user data at scale
- Distributed systems logic: concurrency, locks, idempotency
- Background jobs with side effects that cannot be undone
- Security-sensitive operations: input sanitization, access control checks
For red code, the approach changes. You either read every line with genuine understanding of what it does, or you write it yourself and use AI as a reference. The risk profile for bugs in these areas is too high to accept “looks right” as your review standard.
The Hard Signals That Tell You to Stop Vibing
There are moments in an AI-assisted session where the vibe breaks down and the signs are specific enough that you should treat them as hard stops.
The AI is toggling between two broken solutions. You ask it to fix a problem. It makes a change. You test and the same problem appears differently. You explain what happened. It reverts and tries a different approach that creates a different version of the same problem. If this happens twice, you are not in a productive AI session anymore. You are in a loop. Stop, step back, and debug the actual problem yourself.
You have explained the same requirement three times. If the AI keeps generating code that violates a constraint you have stated explicitly, the context is broken. Either the constraint is not in the model’s effective context window, or there is something in the codebase that keeps pulling it back to the wrong behavior. Using context engineering principles to give the model better information about the constraint before trying again will get you further than repeating the instruction.
The diff is growing but the feature is not advancing. More code is not more progress. If each iteration adds lines without meaningfully moving toward the goal, the model is thrashing. This is the point to write the core logic yourself and use AI for the parts around it.
The code review would take longer than writing it. This is the most important stopping signal. Before you merge any AI output, do a quick estimate: how long would it take to read this diff with enough understanding to genuinely know it is correct? If that estimate exceeds five minutes and the code is in a yellow or red category, you should read it. If the review would take longer than it would take to write the code yourself, that is a signal about the complexity of what was generated. Complex AI output in high-risk areas is where bugs hide.
Connecting the Framework to Spec-Driven Development
The vibe ceiling framework tells you where to draw the line on any given piece of AI output. Spec-driven development tells you what to do when you decide not to trust it.
These are complementary tools. The framework is real-time and per-decision. The spec approach is pre-work that raises the quality ceiling for everything the AI generates.
When you write a detailed spec before asking the AI to implement something, you are doing context work that shifts more code from yellow to green. The model has better information, generates more accurate output, and the decisions it makes are more likely to match your actual requirements. Context engineering at the task level does the same thing.
A good workflow looks like: spec first for anything in yellow or red territory, apply the three questions to any diff before merging, use the code-type classification as a quick filter for how much review depth you need.
Recalibrating Your Confidence
The METR study is not an argument against using AI tools. It is an argument for recalibrating confidence to match actual risk.
On greenfield code, experienced developers with AI tools accelerate significantly. The ceiling is high because the risks are lower and reversibility is better. Trust more, review lighter, ship faster.
On mature codebases with business-critical logic, the ceiling is lower. Not because the tools are worse, but because the cost of a wrong decision is higher and the plausibility trap is stronger. Your familiarity makes broken code look right. Slow down on the things that matter.
The developers who get in trouble are not the ones who distrust AI output on everything. That is just slow. The developers who get in trouble are the ones who apply the same level of trust to all code regardless of risk, let the vibe override their judgment on the wrong things, and discover the technical debt and security issues that result three months later.
The framework is not about using AI less. It is about being precise about where your trust is calibrated correctly and where it is not.
The Honest Version
After a year of working with AI coding tools daily, my practical summary is this: the vibe ceiling is real, it hits experienced developers harder than juniors on mature codebases, and the perception-reality gap does not go away on its own.
The three questions cut through it. Blast radius, reversibility, and “would I approve this PR” give you real information in under a minute. The code-type classification gives you a default starting point. The hard stop signals tell you when to change approach entirely.
None of this requires trusting the AI less in general. It requires trusting it less in the specific places where the cost of being wrong is high. That is not caution. That is just calibration.
Ship fast where fast is appropriate. Review carefully where careful is required. The framework gives you a way to tell the difference in the moment instead of finding out the slow way.