AI code generation

The diff you can read, but can't trust.

Your AI writes a diff that compiles, passes the tests you showed it, and looks locally coherent. The codebase has its own unwritten rules - the patterns it actually keeps across hundreds of files. The model sees only the slice you gave it. The rules live in the whole. And they move under you every time the model, the prompt, or the part of the repo changes.

What it sounds like from the desk

These are engineers and leads, in public, describing the ordinary week with AI-generated changes.

“The AI added a helper that duplicates logic we already have in three other places. It didn’t know because the context window only saw the file I was editing.”

engineering lead (pattern reported across HN and internal reviews)

“It used a broad except: pass. Our house rule is explicit except for the three places we document it. The reviewer caught it, but we almost shipped it.”

recurring in Claude Code GitHub issues and r/tifu incident reports

“Every new model release changes the ‘style’ of the diffs. Last week it loved early returns. This week it inlines everything. The reviewer has to re-learn the model’s current tic.”

staff engineer pattern, Hacker News threads on AI coding assistants

“I asked it to add input validation. It added it in the handler but skipped the same check in the background worker that calls the same path. Two places, two truths.”

common scope-understated failure mode in agentic PR studies

“The docstring now names a parameter the function no longer accepts. The model updated the body but left the docs. Classic drift.”

docstring drift, a common pattern in AI refactors

“We have 47 open PRs from the agent this month. Every one needs a human to hold the entire repo’s conventions in their head. We are the expensive context window.”

the human as the expensive context window, a widely reported review-load pattern

Voices reflect patterns repeatedly attested in public sources: Hacker News threads on AI coding assistants, Reddit (r/tifu, r/ExperiencedDevs), and GitClear's analysis of 211 million lines of changed code, which found code churn roughly doubling (3.3% to 7.1% of lines, 2021 to 2025), copy-pasted code rising from 8.3% to 12.3%, and refactoring falling from 25% to under 10% of changes. The quotes are representative composites grounded in those records, not verbatim one-liners.

This is not a feeling. It is structural.

The model optimizes for the next plausible token given the slice it sees. The codebase optimizes for consistency across the whole. These two objectives are misaligned by construction, and they drift independently.

Model update
A new model version ships. The statistical distribution of “good” code shifts overnight - new favorite patterns, new omission modes, new ways of naming things. Every prompt that worked last week now produces slightly different conventions. operational
Prompt / agent change
You or your agent tweaks the system prompt, adds new examples, or changes temperature. The output style moves. The repo did not. operational
Scope expansion
The change touches a module the model has not seen in this session. The local conventions of that module are invisible. The diff is correct in the file, wrong for the neighborhood. operational
Repo evolution
A refactor lands. A new lead establishes a different error-handling idiom. The old patterns are still in 80% of the files. The model has no single source of truth for “how we do it here now.” structural
Context cliff
Any single diff is small. The rules it must obey are distributed across the repo. When the change is non-trivial or the repo is large, the model cannot hold the relevant precedents. It fills with the most common internet pattern instead of your house pattern. structural

The operational drift is frequent and cheap to detect after the fact. The structural misalignment is constant and expensive to prevent.

The shape of the problem

One repo has hundreds of files. They all lean on a small set of stable house conventions. The AI sees one file (or a retrieved slice). The reviewer has to hold the whole in working memory.

“The AI used a different error pattern here.”
“A new helper that duplicates existing logic 40 lines away.”

Left: your codebase files, grouped by area. Right: the small, stable set of house conventions the repo actually keeps. The tangle between them is the work a reviewer does by hand, one diff at a time. illustrative   The live map for any public repo is at code.doloop.io/cli

What actually changes, and how often

The repo’s core conventions are remarkably stable once a codebase matures. It is the inputs to the AI that keep moving. Ranked by how often it bites a team:

OFTEN
The model or prompt this week. A release or a tweak changes what the AI considers idiomatic. The repo did not move.
OFTEN
The slice the model sees. Retrieval, recent files, or the active file only. Precedents outside the window are invisible.
OFTEN
Which part of the repo is touched. New module, new service, new data shape. Local conventions differ; the model has no persistent map.
RARELY
The repo’s own settled conventions. Once a pattern is held at 85%+ across sites, it changes only on deliberate refactor. That is the durable signal.
AT ONCE
A model regime change or major refactor. Everything that was “how we do it” is now in motion at the same time. Review load spikes across the org.

None of the frequent changes is a rewrite of the repo’s actual behavior. The durable signal is there. The delivery mechanism (the model’s context and training distribution) is what drifts - which is exactly what a per-prompt RAG or a one-time fine-tune cannot keep up with.

Why the usual fixes don’t hold

Each common approach assumes something the structure above shows is false.

Full-repo RAG every time

Retrieve the whole codebase or relevant chunks into the prompt so the model “sees” the conventions.

Token cost explodes with repo size. Snapshot goes stale the moment code lands. The model can still generate a locally plausible violation because it is still generating, not verifying.

Fine-tune or LoRA on the repo

Train the model on your codebase so it internalizes the house style.

Expensive to keep current. Still probabilistic - it can confidently produce the 6% case. A single refactor invalidates large parts of the tuning. You are now maintaining a model, not just code.

Generic linters + type checkers + human review

Run ruff/black/mypy and have a senior reviewer read every diff.

Catches language-level issues. Misses house rules that have no linter ( “we swallow only in these three files”, “index parameters are always bounds-checked here”). The human reviewer becomes the expensive, inconsistent, non-scalable context window.

What it costs, quietly, every sprint

Review time

Every AI diff gets a human pass that must hold the whole repo’s conventions in working memory. Volume scales; attention does not.

Inconsistency debt

Small violations accumulate. Over months the codebase develops two (or three) ways of doing the same thing. Onboarding and maintenance cost rises.

Slipped defects

A “correct” diff that violates an implicit safety pattern ships. The bug is real even if tests pass.

AI onboarding tax

Every new session, every new model, every new teammate has to re-learn or re-prompt the house rules. The knowledge is not portable.

There is a way to hold this.

The doloop CLI was built for exactly this world. It reads your entire repo (or any public GitHub) locally, builds a deterministic map of what the code actually does and how, infers the house conventions with their holding rates, and then for any staged change or proposed diff it tells you exactly which rule it breaks, the line, and how often the rest of the codebase does it the other way. It never guesses. When it cannot place a verdict with certainty it flags a gap. Human rulings on exceptions are recorded and re-applied. It emits the living rule set to AGENTS.md, CLAUDE.md, or Cursor rules so your AI starts from the right place. Same input, same verdict, every run. Your source never leaves your machine.

doloop code · deterministic checks, local, bring your own modelcode.doloop.io/cli