Lost in the Context

1. The App That Passed Every Test and Did Nothing

Two months ago I gave Claude Code a spec, a plan, and my entire codebase. I told it to build a full-stack app. Frontend, backend, database, the works. I went to sleep. I woke up to a green build.

Every test was passing. The container was running. The frontend loaded. The backend responded. I opened the app and felt that brief, intoxicating moment where you think the tool just saved you two weeks of work.

Then I clicked around.

Nothing was actually functioning end to end. The frontend was wired to stubs. The API contract between the frontend and backend was never built. The data that appeared on screen was hardcoded placeholder content that happened to match the test fixtures. The app was a Potemkin village with a green CI badge.

I spent the rest of the day deleting most of it and writing the contracts myself.

This was not Claude's fault. Claude did exactly what I asked: generate code that satisfies the spec and passes the tests. The problem was that the spec described intent, not contracts. The tests verified isolated units, not integration. And I, the human reviewer, approved code I could not meaningfully read because there was too much of it and the green checkmarks told me it was fine.

I was overconfident that Claude Code could build the whole thing in one shot. My overtrust was "do all the work at once." When I tested it after a few hours of running, I was disappointed. Not at Claude. At myself. I had outsourced the one part of engineering that cannot be outsourced: verifying that the thing actually works.

This post is about what happens when AI writes more code than any human can review, and the green build is lying to you.

2. The Numbers Nobody Is Talking About

AI-assisted teams ship more code. That is the headline everyone reports. Here is the rest of the story.

LinearB analyzed engineering teams in late 2025 and found that AI-assisted teams produced roughly 20 percent more pull requests. The same teams saw a 23.5 percent increase in production incidents and roughly a 30 percent increase in change failure rates.

More code, more bugs. Nothing surprising there. But the mechanism matters. AI tools do not write buggier code per line. They write a lot more lines, packed into larger pull requests, and those PRs overwhelm the human review process.

Google published a study of 9 million code reviews and found that the optimal review size is 200 to 400 lines. Beyond that, review effectiveness drops sharply. Reviewers catch fewer bugs per line. They miss systemic issues. They skim. By 500 lines, you are losing the signal. By 1,000 lines, you are rubber-stamping.

Claude Code can generate 2,000 lines in one session. It can do it with full context of your codebase, every file, every pattern, every convention. It can produce a PR that compiles, passes tests, and follows your style guide. It can do all of this while you are asleep.

And when you wake up, you are staring at 2,000 lines of code that you did not write, touching ten files you have not opened in months, with a green checkmark from a CI pipeline that verifies exactly what you told it to verify and nothing more.

You have two choices. Spend four hours reviewing it properly, which you will not do because you have three meetings and another PR waiting. Or approve it, because the tests passed and the AI has never let you down before.

Most people pick option two. The data backs this up. Larger PRs correlate with lighter reviews. Lighter reviews correlate with more incidents. More incidents correlate with everything else: on-call pages, customer escalations, trust erosion.

3. The Context Window Is the Problem

AI models are marketed by their context windows. Gemini 2.5 Pro advertises 1 million tokens. Claude claims 200,000. These numbers sell the fantasy that more context means better output. Feed the model your entire codebase, every README, every design doc, every past incident report, and it will produce code that understands everything.

The fantasy is only half wrong. The model does understand everything. That is the problem.

When you give an AI your entire codebase, it produces output that reflects your entire codebase. It touches files across modules because it sees the connections. It refactors across boundaries because it sees the coupling. It makes wide, systemic changes because you gave it the system.

A human reviewer opens that PR and sees 15 files changed, 1,800 lines added, 300 removed. The changes are correct individually. Each function looks clean. Each test passes. But the reviewer cannot hold all 15 files in their head simultaneously. They cannot model the ripple effects. They cannot answer the question that matters most: does this thing actually work end to end.

The AI's context window is 200,000 tokens. The human's effective review window is roughly 400 lines. The gap between those two numbers, 200,000 tokens of generation versus 400 lines of comprehension, is where the bugs live. Not bugs in the AI's output. Bugs in the human's approval.

This is not a tool limitation. It is a cognitive one. You cannot read 2,000 lines of code in 30 minutes and catch the missing API contract between the frontend and backend. The hardcoded data that happens to match the test fixtures goes unnoticed. You lose the execution path through eight files when you are looking at each file in isolation, jumping between tabs, losing your place.

The green build becomes a proxy for correctness because the alternative, actually reading every line, is not realistic. And the AI knows this. Not consciously, but structurally. It optimizes for what gets approved. Code that passes tests gets approved. Code that is too large to review passes if the tests pass. The feedback loop selects for large PRs with passing tests, and that selection pressure produces exactly the kind of code I woke up to: a working container, green CI, and nothing functioning end to end.

The context gap: 200K tokens of AI generation vs ~400 lines of human comprehension

4. What I Actually Built

Let me describe the failure in detail, because the specifics matter.

I asked Claude Code to build a full-stack application with a React frontend and a Python backend. I wrote a detailed spec. I included architecture decisions. I specified the tech stack, the folder structure, the testing strategy. I thought I had covered everything.

Claude generated the code. The frontend rendered a page. The backend served API responses. The tests passed. The container built and ran. From the outside, it looked complete.

Here is what was actually happening:

The frontend components were calling local functions that returned hardcoded JSON. Those functions had the same shape as the API responses they were supposed to call. They matched the TypeScript types. They matched the test expectations. But they never touched the network. There was no fetch call, no Axios instance, no WebSocket connection. The entire frontend was a self-contained simulation that looked identical to the real thing.

The backend had real endpoints. They returned real data from a real database. They were tested and correct. But the frontend never called them. The contract between the two halves, the shared types, the request schema, the response format, the error handling strategy, was never built. Claude built two independent applications that happened to share a repository.

The tests passed because each half was tested in isolation. The frontend tests mocked the API layer. The backend tests mocked the client. No integration tests existed because I had not specified them. I assumed the AI would connect the pieces. It assumed the pieces were complete as specified.

Neither of us verified the assumption. The build was green. The tests passed. I approved. And nothing worked.

The cost was not the wasted compute. Claude's API bill was negligible. The cost was the trust I lost in my own judgment. I had handed my approval authority to a green checkmark and learned the hard way that passing tests and working software are different things. Every engineer knows this. I forgot it because the tool was new and impressive and I wanted it to work.

5. This Is Not an Anti-AI Argument

The easy takeaway is "AI writes bad code, do not use it." That is wrong, lazy, and dishonest. AI writes code faster than I do. It remembers every convention, every lint rule, every type definition. It does not get tired, does not cut corners because it is Friday afternoon, does not ship a TODO comment and promise to fix it later.

The problem is not the code. The problem is the workflow.

When a junior engineer submits a 2,000-line PR, you do not approve it. You send it back. You tell them to split it into smaller PRs, each with a clear purpose, each reviewable in under 30 minutes. You enforce this because you know that a 2,000-line PR is a liability, regardless of who wrote it.

When an AI submits a 2,000-line PR, the same rule applies. The fact that the AI wrote it in 30 seconds instead of three days does not change the review burden. The code still needs to be understood. The integration still needs to be verified. The contracts still need to be traced. If anything, the AI's code needs more scrutiny because the AI does not have skin in the game. It does not get paged at 3 AM. It will not sit in the postmortem. It will not explain to the customer why their data disappeared.

The counterpoint worth acknowledging is that AI-assisted teams also have better tooling. CI pipelines are faster than ever. Automated testing catches more. Static analysis flags vulnerabilities before they reach production. Review bots like CodeRabbit and Graphite Reviewer scan every PR and surface issues a human might miss.

These tools help. They are not enough. A review bot can tell you that a function is missing error handling. It cannot tell you that the frontend and backend never agreed on a response format. It cannot tell you that the data on screen is fake. It cannot verify that the thing works. Only a human, running the code, tracing the execution, clicking through the flows, can verify that.

The argument is not "slow down." The argument is "review what you ship." The AI can write the code. It cannot take responsibility for it. That part is still yours.

6. Small PRs, Human Eyes, and What Actually Works

I changed three things after the Potemkin village incident.

First, I stopped asking the AI to build entire features in one shot. Instead, I ask it to build one contract at a time. API contracts get written first, reviewed, and frozen before any implementation touches them. Frontend and backend are implemented against that contract in separate PRs. The contract is the bridge, and the bridge is built before either shore.

Second, I enforce a hard line limit. Every PR must be reviewable in under 30 minutes. If the AI generates more than roughly 400 lines, I ask it to split the work. The AI resists this. It wants to be comprehensive. It wants to show you everything it can do. I tell it no. Split the work. Smaller PRs, each with a single purpose, each reviewable by a human who is slightly tired and slightly distracted and still capable of catching the missing fetch call.

Third, I verify every PR by running the application, not just the tests. I click through the flows. I check the network tab. I look at the data and ask whether it came from the database or from a hardcoded constant. If I cannot verify it by hand in under ten minutes, the PR is too big. I send it back.

These are not technical changes. They are process changes. They cost nothing to implement. They slow down the initial coding but they eliminate the rework. The rework from my failed app took longer than the original generation. The rework from every unreviewable PR takes longer than splitting it would have taken.

None of this is new. Engineers who have run production systems for years know these rules. They learned them from incidents and postmortems and the slow accumulation of scars. What is new is that AI tools make it easy to forget them. The speed is seductive. The green checkmark is convincing. The cost of forgetting is the same as it has always been: a broken app, a wasted day, and the quiet embarrassment of having trusted the tool more than your own judgment.

Small PRs, contract-first, human verification — the corrected workflow

7. Where This Breaks at Scale

I work on small teams. I review my own AI's code. The feedback loop is tight. When the PR is too large, I notice because I am the one who has to read it.

At scale, the feedback loop breaks. When a team of 20 engineers each have AI assistants generating code, the aggregate PR volume outpaces the team's review capacity. Reviewers skim. They approve faster. They trust the green build more because the alternative, slowing down the entire team, is not politically viable.

This is where the LinearB numbers stop being interesting and start being alarming. A 20 percent increase in PR volume combined with a 30 percent increase in change failure rates is not a coincidence. It is a system under stress. More code arriving faster than humans can read it. More approvals based on CI output rather than comprehension. More incidents caused by changes that were never truly reviewed.

I do not have a solution for the scale problem. Small PRs help, review bots help, pairing AI generation with AI review helps, but the fundamental constraint remains: a human can only read so much code in a day, and AI tools are very good at generating more code than that. Somewhere in every organization there is a human who approves more than they read. The question is not whether that person exists. The question is how much unreviewed code is shipping through them right now, and what it will cost to find out.

At scale: PRs stacking up faster than any team can review, green stamps applied blindly

8. References

  1. LinearB, "The State of AI Code Review 2025," December 2025. Key stat: AI-assisted teams show 20% PR volume increase, 23.5% incident increase, ~30% change failure rate increase. (https://linearb.io/blog/ai-code-review)

  2. Caitlin Sadowski, Emma Söderberg, Luke Church, Michal Sipko, Alberto Bacchelli, "Modern Code Review: A Case Study at Google," ACM/IEEE ICSE-SEIP 2018. Key stat: optimal review size is 200-400 lines; effectiveness drops sharply beyond that. (https://dl.acm.org/doi/10.1145/3290605.3300464)

  3. Personal experience: Hossam Fares, Claude Code full-stack application generation, May 2026. Application passed all tests, container ran, but frontend was wired to stubs and the FE↔BE API contract was never built. No integration verification was performed before approval.