When AI Changes Code You Didn't Ask It to Touch

You asked for one small change. The diff shows four files.

Sometimes the extra changes are improvements. Sometimes they quietly remove something you needed. Either way you now have a decision to make about work you never requested, and no easy way to tell which parts were the thing you actually wanted.

Why it happens

There are three common causes, and they call for different responses.

The request was broader than you thought. "Fix the date formatting" does not identify a place. If dates are formatted in five files, a reasonable reading of that instruction is to fix all five. The change was not out of scope; the scope was never stated.

Nothing marked the surrounding code as settled. The AI can see the rest of your code, and nothing in it says "this part is finished and correct". Code that looks inconsistent, repetitive or old-fashioned reads as an invitation. Left to its own judgement, a model will often improve what it finds on the way past — that is usually desirable behaviour, and it is exactly what you do not want in the middle of a specific change.

The fix genuinely required it. Occasionally the extra edits are load-bearing: the change could not work without them. This is the case worth slowing down for, because it is telling you something true about the shape of your code — and it is the only one of the three where accepting the wider change may be right.

What to do right now

If it has just happened, resist the urge to ask for a correction immediately. A correction on top of an unclear change gives you two unclear changes.

Work out which files you expected to be touched, and which were not. That list is the actual problem, and you can usually produce it in under a minute.

Then check whether the unexpected edits broke anything. Look at the two or three things nearest to them that were working before. This matters more than reading the changes: a rewritten function that still behaves identically is untidy, whereas a "harmless tidy-up" that changed a default is a real fault hiding in plain sight.

Then choose deliberately. If the extra work is genuinely fine and you have checked it, keep it and note that it happened. If it is not, go back to your last known-good state and ask again with tighter bounds — rather than asking for the unwanted parts to be undone, which leaves you relying on the same judgement that produced them.

This is the point at which having something to return to stops being theoretical. If you cannot answer "what was the last version I knew was correct?", the problem is no longer this change.

How to stop it happening again

Say what must not change, in the request itself.

Instructions describe the work. Constraints describe the boundary. Most people write the first and assume the second, and the assumption is not shared. Compare:

Fix the date formatting on the invoice list.

with:

Fix the date formatting on the invoice list. Change only the invoice list template. Do not alter the invoice model, the CSS or any other page. Leave the existing sort order exactly as it is.

The second is barely longer to write and gives you something far more valuable: a change you can review in a minute, and a clear basis for rejecting it if it arrives wider than agreed.

Three things are usually worth naming explicitly, because they are the ones most often changed in passing:

  • Files or areas that are off limits — particularly anything shared, like styling, configuration or a data model.
  • Behaviour that must survive — "the existing filters must keep working exactly as they do now".
  • Dependencies — "do not add any new library for this". Otherwise a small feature can arrive with a new package attached.

Bound the change without dictating the solution

There is an opposite failure, and people who have been caught out once tend to walk straight into it. Having discovered that unstated boundaries get crossed, they start specifying everything — which functions to use, how to structure it, where each piece should live.

That gives away the part AI is genuinely good at. Worse, it produces a result you cannot really evaluate: you asked for a particular implementation, you received it, and the only question left is whether it matches your instructions rather than whether it does the job.

The distinction that keeps both benefits is between the edges of a change and its interior. Edges are yours: which files may be touched, which behaviour must survive, what may not be added. The interior is not: how the thing is built inside those edges is exactly the decision worth delegating.

Two versions of the same constraint show the difference:

Do not alter the invoice model or the CSS. The existing sort order must behave exactly as it does now.
Put the formatting in a helper function at the top of the template file and call it from the loop.

The first bounds the change and leaves the work open. The second is a design decision issued as an instruction, and it will be followed whether or not it was a good idea. If you find yourself writing the second kind, it is worth asking whether you would actually mind another approach — and if you would not mind, leaving it out.

Ask for less at a time

Broad edits are much more likely when the request itself is broad. A change that touches one behaviour has an obvious boundary; a change described as "improve the reports section" does not, and no amount of constraint-writing will fully rescue it.

If you find yourself repeatedly receiving more than you asked for, the size of the request is usually the real cause. Choosing the right size of increment removes most of the problem before constraints are needed.

Why this one is worth taking seriously

An unrequested change that works is not harmless. It is an edit you did not review, in a place you were not looking, that you now believe is fine.

A few of those, accepted quickly on a busy afternoon, is how a project stops being something you understand. That process has a shape and a set of warning signs: how AI projects drift.

All articles