AI coding tools do not choose the path of least resistance out of laziness. They optimize for whatever is already in view: the nearest module, the function already open, the smallest possible diff. That local logic quietly produces global mess, one defensible import at a time.
The Details:
- Every generated change is locally rational and globally corrosive. Pulling from a module already in scope, or adding one more parameter to an overloaded function, produces a smaller diff than building something new, so the model takes it. Six months later those small choices compound into a system nobody fully recognizes.
- Training data baked in the habit, but memory prevents the fix. Human developers learn from getting burned by tangled code and slowly get more careful. A model starts every session fresh, with no scar tissue from the last mess it made, so the same shortcut gets taken again and again.
- Code review asks the wrong question. Reviewers check whether a diff is correct, not what new dependency it just introduced. Diffs look fine in isolation; the damage only shows up in aggregate, like vines spreading unnoticed across a garden until the paths disappear.
- Comments and architecture docs are not boundaries, they are suggestions. A model treats the codebase as a flat surface and will cross any line that exists only in a person's head or a diagram nobody opens. The fix is a machine-enforced rule, an import linter or dependency rule that fails the build, so the boundary cannot be walked through by anyone, model or human.
Bottom Line: A boundary that only lives in memory will get crossed eventually. One rule that turns red on violation protects it permanently.