Skip to content

Drift Without Restructuring

A codebase is being maintained primarily through AI-assisted edits. The LLM is asked to add features, fix bugs, and adjust behavior. It does so responsively — it patches, extends, and adds. It does not spontaneously restructure code that has accumulated inconsistencies, dead branches, or conflicting conventions, because LLMs act when asked, not when they notice.

Primarily behavioral, accumulating slowly. The cognitive cost stays low for the LLM because each individual change is small and well-scoped. Behavioral cost (subtle bugs, performance pathologies, security holes that emerge from inconsistent handling across paths) accumulates invisibly until something breaks.

  • Two slightly different code paths handle “the same” case differently. A bug shows up only when the rare second path is exercised. The LLM’s per-change scope didn’t surface the divergence.
  • Dead code accumulates. Old patterns coexist with new ones; both are kept “in case.” The LLM, asked to add a feature, often adds another pattern rather than reconciling.
  • Performance pathologies compound. Each individual addition is cheap; the sum exhibits N+1 queries, redundant renders, or memory growth. The LLM’s perspective is local to the change.
  • Security and validation become inconsistent. Some paths sanitize input; others were copy-pasted before the sanitization was added. The LLM doesn’t propagate retroactively unless asked.
  • The LLM has been asked to make 50+ changes; you have not asked it to “review the structure” or “reconcile the patterns” once.
  • A new change required the LLM to first explain to itself what the existing patterns are. The patterns are no longer self-evident.
  • You’re noticing duplicate-feeling code in PRs but you haven’t been pulling on the thread because each individual diff is reasonable.
  • Bug investigations reveal multiple slightly-different versions of the same logic.
  • Performance regressions that nobody introduced — they emerged from the sum of unrelated changes.
  • A dependency upgrade or environment change exposes inconsistencies that “always worked” but were latent.
  • Security audits surface “why is this path doing X differently?” answers that nobody can give.
  • Periodic structural review, prompted explicitly. Ask the LLM to look across the codebase for duplication, divergent patterns, dead code, and inconsistent handling of cross-cutting concerns. This is a different mode than per-feature work and has to be invoked separately.
  • Reconciliation as a first-class task. When the LLM proposes a change that introduces a third variation of an existing pattern, that’s the moment to consolidate, not to add the variation.
  • Boundary tests that exercise multiple paths through similar logic. If two paths exist that should behave the same, test them with the same inputs and assert the same outputs.
  • Don’t use the LLM as the only reader. Periodic human review of structure (not line-by-line correctness) catches the kind of drift the LLM doesn’t surface.
  • Codebases that are short-lived enough that drift won’t accumulate (genuine prototypes, single-shot scripts).
  • Codebases where the structural review is happening, just not visibly — for example, when the human author is doing their own occasional reread and reconciliation pass.

This is the failure mode that distinguishes “AI-collaborated” from “AI-maintained” code. Collaborated work has a human steering at the structural level; maintained work has the LLM steering with the human only steering individual changes. The latter regime accumulates drift the former does not. Most practices for AI-collaborated work assume the former; the latter needs its own discipline.