A senior developer we worked with spent two hours on an agent-generated pull request last month. Two hours is a serious review. He read every line. He checked the tests. He traced the main path twice.
He approved it, and it was wrong.
What made it interesting is that a junior on the same team had flagged the problem in fifteen minutes. Not because she was better. Because she had no idea how the code was built, so she never tried to follow it. She just asked what happens when the list is empty, and went looking.
The senior developer had done what he always does. He read the code the way he writes code: from the top, following the flow, building understanding as he went. That method worked for twenty years. It is now the thing that failed him.
What the old loop actually trained
We tend to describe the skill as "writing code," which hides what was really being learned.
When you build something manually, you work in small steps and you verify continuously. You write a function, you run it, it fails, you fix it. You add the next piece on top of a foundation you have already checked. By the time the feature is done, you have never once been holding a large piece of unverified work. Correctness compounded.
That is a specific cognitive habit, and it is a good one. It taught us to think in sequence. To trust progress. To treat "it runs" as meaningful evidence, because when you built it incrementally, it was.
It also meant you never had to read a big artifact cold. You already knew what it did. Reading your own code back is not comprehension; it is recall.
Everything about that habit assumed one thing: that the person reasoning about the code and the person producing it were the same person, working at the same time.
The assumption broke
An agent hands you the finished thing.
There were no small steps you verified. There is no foundation you checked. There is a complete artifact, produced by reasoning you did not witness, and your job is to decide whether it is correct.
The old habit does not just fail here. It actively misleads, in four specific ways.
"The tests pass" stops being evidence. It used to be a real signal, because your tests grew alongside your understanding of the problem. Each one encoded something you had discovered while building. Agent-written tests encode what the agent anticipated. They test the same subset of reality the implementation handles. Green means the code is consistent with itself.
Reading top to bottom stops working. You read that way because you wrote that way, and the sequence carried meaning. Agent-generated code has sequence but not history. Following it linearly gives you a narrative of what happens, which feels like understanding and is not. You end up able to describe the code without being able to predict it.
Structure stops being evidence of thought. This one is subtle and it catches experienced people hardest. Clean structure used to cost something. If a function was well decomposed with sensible names, a human had thought about it, and that was information you could legitimately use. That signal is now free. Coherent structure tells you nothing about whether anyone reasoned about the domain.
Debugging by re-reading stops working. When something failed, you reread the code and the memory of writing it came back with it. That is why it worked. Reread code you never wrote and there is nothing to come back.
What the junior developer did differently
She did not read the code. She asked what would break it, and then went looking for that specific thing.
That is the whole shift, and it sounds smaller than it is. She started from the outside: what are the inputs, what is claimed about the outputs, where is the boundary. Then she went hunting for one case. She was not building a model of the code. She was trying to break a claim.
Call it adversarial reading. You begin from the assumption that the artifact is wrong, and your task is to locate where. That is a different posture from building understanding, and it produces a different search pattern. You go to the boundaries first: empty, zero, one, maximum, negative, null, concurrent, the second call. You go to the error paths, which is where agents are weakest, because error handling is the part of a specification people leave out.
Here is the kind of thing it finds. This function was in the PR:
def apply_discount(items, code):
total = sum(i["price"] * i["qty"] for i in items)
pct = DISCOUNTS.get(code)
if pct:
total = total * (1 - pct)
return round(total, 2)
Read it linearly and it is fine. The names are good, the arithmetic is right, the rounding is there, and a test with a normal cart and a valid code passes.
Now attack it. What is DISCOUNTS.get(code) when the code is invalid? None, and if pct is false, so we skip the discount and charge full price. Silently. No exception, no log, no signal. A customer types a promo code that expired, and we charge them the full amount and tell them nothing. That is not a crash; it is a support ticket three weeks later, and a trust problem you will never fully measure.
There is a second one in the same three lines. What if a discount is legitimately zero percent? if pct is false again, and the two cases are now indistinguishable. The bug and the valid case share a code path.
Nothing about reading that function from the top surfaces either problem. You have to arrive with the question.
This is exactly the exercise a well-designed interview now runs, which we covered in Part 3. The interviewer is not checking whether you can read. They are checking whether you arrive with the question.
Why seniority makes this harder
The uncomfortable part is that the reflex gets stronger with experience.
Twenty years of incremental building produces a very good instinct for following code, and that instinct fires automatically. It does not present itself as a choice. You look at a diff and you are already reading it the old way before you have decided anything.
Junior developers do not have the reflex yet. That is why the fifteen-minute catch was not luck. She had nothing pulling her towards linear reading, so the obvious question was available to her.
This is not an argument that inexperience is an advantage. The senior developer has the domain model that makes the question "what happens with an invalid code" produce a list of consequences rather than a shrug. The advantage is real; it is just being spent on the wrong activity. He used his two hours to reconstruct the code. He should have used ten minutes of it to interrogate the contract.
Part 2 of this series covered the research showing which skills atrophy under AI assistance. This is the mechanism underneath the numbers. It is not that people get lazy. It is that a highly trained, previously correct habit keeps running in a situation where it no longer applies.
It also explains why the Interview Skill Map moved the way it did. Output evaluation rose to the top not because reading code became more important, but because a specific kind of reading became necessary and almost nobody had been practising it.
What to replace it with
Three changes, in the order they are worth making.
Reconstruct the contract before you read the implementation. Before opening the diff, write down what this code must be true about: valid inputs, expected outputs, what counts as failure, what must never happen. Two minutes, from the ticket rather than the code. Now you are reviewing against something. Without it you are only checking whether the code agrees with itself, which it always will.
Read for the failure, not for the flow. Pick the boundaries and go straight there. Empty, zero, one, maximum, malformed, absent, repeated. Do not start at line one. Starting at line one is the old habit wearing a review hat.
Treat "I can describe it" as insufficient. The test is prediction, not description. Can you say what this returns for an input you have not seen? If you can only narrate what the code does, you have followed it rather than understood it. Those feel identical from the inside, which is exactly why the two-hour review approved a broken function.
None of this is slower than what most people do now. The senior developer's two hours were not wasted because he was careless. They were wasted because the method was built for a situation that no longer exists.
If you want to drill it rather than just agree with it, the interview prep coach runs this as a scored exercise in your own stack: it plants one real behavioural bug among genuine style flaws and tells you how far you read before you found it. Most people fail the first attempt, which is the point.
The thing this connects to
Part 4 argued that the cognitive work has to move to before the agent runs. This is the other half: the work that remains after the agent runs is not the work you are trained for either.
Specification moved earlier. Evaluation moved later and got harder. The comfortable middle, where you built the thing and understood it by building it, is the part that disappeared, and it was the part that carried both skills for free.
If you are not sure which pattern you are in, Part 1 has the five-question self-check.
The next article is about the first half of that: what a specification an agent can actually execute looks like, and why most of what we call requirements are not specifications at all.
© Gabor Mayer. Licensed under Creative Commons Attribution 4.0 (CC BY 4.0). Free to share and adapt with attribution.
