Intro
There's a gap between the way AI-assisted coding gets demoed and the way it actually gets used under a deadline. In the demo, the model writes a function, the developer reads it, understands it, and merges it. Under a deadline, the model writes a function, the developer skims it, it looks plausible, and it merges. Same tool, two completely different outcomes, and the difference isn't visible in the diff.
Call the first one cognitive assistance: the AI removes typing, not thinking. Call the second one cognitive offloading: the AI removes thinking, and the developer just does the typing that's left, mostly pressing "accept." Both look identical in a pull request. They only diverge later, when something breaks and someone has to explain why the system does what it does.
Here's where that gap actually shows up in production. (Illustrative composites drawn from common patterns, not specific incidents.)
The schema nobody actually reasoned about
A developer asks an AI assistant to generate a migration adding a new table with two foreign keys. It looks right, it runs locally, tests pass, it ships. Nobody on the team, including the person who wrote the migration, actually worked through the access pattern the new table would see in production. Three months later, a dashboard query against that table starts timing out under real traffic, because there's no index on the column it's actually filtered by, a detail that would have been obvious to anyone who'd designed the schema by hand instead of approving one.
The stack trace that got forwarded, not read
Someone hits a NullPointerException, pastes the trace into an AI chat, gets back a suggested null check, adds it, ships it. The exception stops. Two sprints later, a related bug shows up somewhere downstream, because the null check treated a symptom, a race condition further up the call stack, not the cause. Nobody connects the two, because nobody who touched the first fix ever understood what was actually racing.
The architecture nobody in the room can defend
In a retro, a tech lead asks why a service makes three synchronous calls to downstream services instead of publishing to a queue. Nobody has an answer, because the pattern was generated during a crunch week, skimmed, and merged. It's not that the pattern is necessarily wrong, it's that no one currently on the team could tell you whether it's wrong, which means no one can safely change it either.
Cognitive offloading isn't really an AI problem. It's a code review discipline problem wearing an AI hat. Teams that had weak review habits before AI tools now get weak review at a much higher volume and velocity, which turns a slow leak into a flood.
A quick gut check, if you want one: before you merge AI-generated code, can you explain it to a teammate without opening the chat history again? Could you have arrived at this approach yourself given more time? Do you know why this pattern and not an obvious alternative? If the honest answer to any of those is no, that's not a blocker, it's just useful information about which side of the line you're currently standing on.
Where do you draw the line between assistance and offloading on your team, is it an explicit rule, part of your review process, or just a gut feeling that kicks in after something's already gone wrong?
Top comments (12)
The gut check you close with is the one that's stuck with me, but I'd push the horizon out. Can you explain it today lets a lot of cargo-culted diffs through, because the merge is when motivation is highest. The test that actually catches the schema-with-no-index case is can you still explain it in three months, when the next person has to touch it and you're not there. I treat agent output as an untrusted patch and make it carry its own reason: what changed, why this and not the obvious alternative, what it can't do. That note is what the next edit argues with, instead of rediscovering the decision from zero. Your line about weak review habits getting a velocity multiplier is the part I keep thinking about. Do you enforce the explain-to-a-teammate step as part of review, or is it still informal?
The three-month version of the test is better than mine, and I think you're right that "can you explain it today" is where a lot of cargo-culted diffs sneak through. Merge time is peak context; you've just been in the chat, you've just seen the tests pass, of course you can narrate it. The real question is whether the reasoning survives once that context is gone, and most of the time it doesn't because it was never externalized in the first place.
I like the framing of agent output as an untrusted patch that has to carry its own reason. That reframes the artifact: the diff isn't the deliverable, the diff plus the "why this and not the obvious alternative" note is. And you're right that the note is what the next edit gets to argue with. Without it, the next person is doing archaeology on a decision that was never actually made, just accepted.
On enforcement: honestly, still informal, and I've been going back and forth on whether to push for something more explicit. The concern is that if you make "explain it to a teammate" a required review step, it either becomes a checkbox ("yep, explained it") or it slows things down enough that people route around it during crunch, which is exactly when you need it most. I'm curious how the untrusted-patch-with-a-reason model works for you in practice — is the "why this and not X" note something you require in the PR description, or does it live somewhere else?
Nobody catches the missing index in review, no matter how carefully they read that migration. You'd have to already know which query hits the table in six months, and that knowledge usually isn't in the PR at all. So the assistance vs offloading line seems to move with how much of the system the reviewer already holds in their head.
Fair pushback, and I think you're right about the specific case. The missing index isn't really catchable at review time unless the reviewer already knows the query that's going to hit the table, and that knowledge usually lives in someone's head, or in a dashboard that doesn't exist yet, not in the diff. So framing it as "a careful reviewer would have caught this" is probably wrong. A careful reviewer reading only the migration couldn't have.
What I think the example actually shows, and what your comment made clearer to me, is that the failure happens earlier than review. It's that the access pattern was never stated anywhere the reviewer could see it. If the PR description had said "this table will be read by the ops dashboard, filtered by tenant_id, roughly on every page load," then the index question becomes obvious to anyone, including the author. Without that, the reviewer is being asked to reconstruct intent from schema alone, which is a job the schema isn't shaped to do.
Which lines up with your broader point: the assistance/offloading line moves with how much system context the reviewer holds. And I'd add that AI-generated code makes the context problem worse in a specific way, because the author might not hold that context either. When a human designs a migration by hand, they usually had to think about the access pattern to write it at all. When an AI generates one from a description of the data model, that step can get skipped entirely, and now neither the author nor the reviewer is carrying the context that would have made the missing index visible. The diff is the same either way, but the amount of reasoning behind it isn't.
So maybe the useful version of the gut check isn't "can the reviewer catch this" but "is the context this code depends on written down anywhere a reviewer could use it." If not, review is being asked to do something it structurally can't.
Spot on! That distinction between cognitive assistance vs cognitive offloading is the cleanest way I've seen it framed.
The 'can you explain it without checking the AI chat history' is such a solid gut check before merging. Great write-up!
Thanks, appreciate it. The assistance vs. offloading distinction was the thing I kept circling back to while writing it, because it explains why two teams using the exact same tool end up with completely different codebases six months later. Glad it landed.
The "architecture nobody can defend" piece rang true. I shipped something once during a crunch that I couldn't explain three months later, and the people who came after me had the same problem, so the whole thing became a section everyone was afraid to touch. The gut check at the end, especially the part about whether you could have arrived at the approach yourself given more time, is the clearest description I've seen of the actual test you should be running at review time. I've started treating it as a literal question to ask in code review, and it surfaces the offloading cases way faster than reading the diff.
The "section everyone is afraid to touch" outcome is the one I think gets undersold, because it doesn't show up as an incident or a bug, it just shows up as velocity quietly dropping in one area of the codebase and nobody being sure why. And once a region of the code has that reputation, it tends to accumulate more of the same, because the next person under pressure also just wants to get in and out without disturbing anything.
Turning the gut check into a literal review question is a good move, and I hadn't thought about using it that way. Reading the diff biases you toward "does this look correct," which AI-generated code is very good at passing, whereas asking "could you have arrived at this yourself" forces the reviewer to actually reconstruct the reasoning instead of just pattern-matching on plausibility. Might steal that. Has it changed what your team ships, or mostly changed what gets sent back for a rewrite?
the cognitive offloading framing is the useful one. most teams conflate 'the PR looks right' with 'someone understood it,' and those aren't the same thing once you're under crunch velocity.
the tell we've seen: code review shifts from 'does this logic hold' to 'does this look plausible.' those are different modes and teams usually don't notice the shift until something breaks in a way no one on the team can explain.
the schema example specifically resonated. an index that's obvious to anyone who reasoned through the access pattern is invisible to anyone who approved a migration that looked correct.
how do you make the review process surface understanding rather than approval?
The "does this logic hold" vs "does this look plausible" split is exactly the failure mode, and I think you're right that most teams don't notice the drift because the review artifact looks identical either way. Same comments, same approvals, same merge cadence. The mode shift is invisible until something breaks in a way plausibility-checking couldn't have caught, which is basically by definition the interesting bugs.
On surfacing understanding rather than approval, I don't think I have a fully worked answer, but a few things that seem to help:
Ask the author to write the "why this and not the obvious alternative" in the PR description, not the code comments. It forces them to have considered an alternative at all, and it gives the reviewer something to actually push on. A PR with no stated alternative is a signal that the design space wasn't explored, it was just accepted.
For anything touching data access, storage, or cross-service calls, require the author to state the access pattern or call pattern in plain language before the reviewer looks at the code. Your schema example is the clearest case: if the author had to write "this table will be filtered by column X at read time, roughly N times per minute" before anyone opened the migration, the missing index becomes almost impossible to miss.
Rotate who reviews. If the same person reviews every PR from the same author, they start pattern-matching on the author's style instead of the code's substance, which is another form of plausibility-checking.
None of these are enforcement mechanisms so much as friction placed at the specific point where offloading tends to slip through. I'm curious what's worked on your side, because the fact that you've named the "logic vs. plausibility" shift suggests you've had to build something around it.
This matches what I keep running into: the code compiles and the tests pass, so nobody reads it until it breaks in a way the tests never covered. I started making myself explain each AI-written diff back in plain language before merging, and the ones I could not explain were almost always the ones that bit me later. The risk was never the generation, it was me approving things I had not actually understood.
The "explain it back in plain language before merging" habit is the one I keep recommending too, and I think the reason it works is that it forces you to translate out of the AI's phrasing and into your own. If you can't do that translation, you've found the gap. Reading the diff doesn't force that step, because you can follow the code line by line without ever building your own model of what it does — you're just verifying that each piece looks like the kind of thing that belongs there.
And your last line is the whole thing, really. The generation is neutral. The approval is where the responsibility actually lives, and that hasn't changed just because the upstream part got faster.