
Cognitive debt is cheap until the code takes money
Cognitive debt costs you a slow refactor in most code and a wrong payment in billing code. How to scale AI review to what breaks when you are wrong.

Cognitive debt does not charge the same interest everywhere in a codebase. Scale how hard you look at generated code to what breaks when you are wrong, because in billing code the bill arrives as a wrong payment rather than a slow refactor.
This post is mostly an argument with one part of somebody else’s work, so let me say up front whose. Addy Osmani has written the clearest account of how AI erodes understanding, across cognitive surrender, don’t outsource the learning and intent debt. The distinction he takes from Steven Shaw and Gideon Nave’s Wharton paper is the one worth carrying: offloading is handing over the work and keeping the judgement, surrender is when you stop forming your own view at all, so there is nothing left to check the output against.
I think the diagnosis is right. What I want to push on is the implied prescription, which is to think harder in general. In the part of the codebase I work in, general is the wrong unit.
Two kinds of debt, two different interest rates
Take an admin screen. You let an agent build it, you skim the diff, you ship. That is debt. The interest arrives months later as a change that takes a day instead of an hour, because you have to work out what the code does before you can touch it. Annoying, recoverable, and nobody outside the team hears about it.
Now the same posture on a renewal handler. The interest is not charged in months and it is not charged in your time. It is charged the first time a webhook is redelivered, and it is charged to a customer.
Three things make that gap wider than it looks.
Revenue failures are quiet by construction. A broken page throws something a human sees. A renewal that fails to extend an expiry throws nothing, because from the software’s point of view the operation succeeded. I went through the specific shapes in six payments edge cases that bite at 2am; most of them share the property that the system reports success while getting it wrong. Osmani’s line is that surface correctness is not systemic correctness. In billing code the surface is worse than merely unhelpful, because it is built to look calm.
The cost lands on someone else first. Debt in ordinary code costs you a bad afternoon. Debt in billing code costs a customer, and then costs you the conversation about it.
Reconstruction is hardest exactly where it matters most. If you do not understand a UI component you can read it and work it out. If you do not understand why a refund path checks a flag before issuing a credit, reading tells you what it does and nothing about what it was defending against. That reason lived in an incident. If nobody wrote it down it is gone, and no amount of reading brings it back.
That last one has a name and a literature. Margaret-Anne Storey’s triple debt model separates technical debt, which lives in the code, from cognitive debt, which she frames as a team-level erosion of shared understanding, from intent debt, which lives in artefacts nobody wrote: the goals, constraints and rationale behind why a system is the way it is. Osmani’s essay on intent debt is where it clicked for me, and his point is the one that bites here. An agent can restore comprehension by reading the code back to you. It cannot restore intent, because asked why a guard clause exists it will produce a confident answer whether or not it has any idea.
Does AI-assisted coding make engineers worse?
On unfamiliar material the evidence points that way, and I want to be careful about how far it goes.
Anthropic ran a randomised trial where engineers learned an unfamiliar Python library, half with an assistant and half without. The assisted group scored around 50% on a comprehension quiz against roughly 67% for the group working by hand, with the widest gap on debugging questions. Anthropic describes that as close to two letter grades. The speed advantage was small enough not to be statistically significant, so on this task the assistance bought almost no time and cost most of the understanding.
The part I keep returning to is smaller and much less certain. Inside the assisted group, the people who came out well were the ones who used the model to build comprehension: some asked only conceptual questions and never had code generated for them, others generated code and then asked for an explanation of what they had just been handed. The worst scores went to people who generated and moved on. The authors are explicit that this is a qualitative observation across a handful of participants and not a causal finding, and the groups involved are single digits. I would not build a policy on it.
But it is the only evidence I have seen pointing at how you asked instead of whether you used it, and it matches something I notice in myself. That is not evidence. It is the reason I bothered to read the study.
Where the posture slips, in money code
Osmani names four moments where surrender happens: reading the diff, debugging something you do not understand, making a design call, and learning something new. I have not found a fifth. What I can add is what three of them cost when the directory is app/Billing instead of anywhere else.
Reading a diff and calling it a review. His version: the tests pass, the names look reasonable, you approve, and what you did was ratify instead of review. The billing-specific question that separates the two is narrow enough to ask every time. What does this do if it runs twice? With at-least-once delivery the second run is normal operation, not an error case, so a handler that is only correct once is a handler that is wrong and has not been caught yet.
Fixing something you cannot reproduce. His version: paste the trace, apply the fix, move on, and your mental model is now wrong somewhere you cannot point to. Here the cost compounds differently. A wrong model of a rendering path costs you one bug. A wrong model of a state transition costs you every bug that transition will ever produce, because the misunderstanding is still sitting there generating them.
Taking the framing along with the answer. His version: you ask queue or direct call, and accepting the answer means accepting the model’s version of the question. The money-code equivalent is whether to store an amount as an integer or trust a library to handle it. I have a position on that, integer cents, never a float, and the reason it is a position instead of a preference is that this is a class of decision you cannot recover from by editing later.
None of that is a new taxonomy. It is his taxonomy with the interest rate recalculated.
The same failure, seen from the other chair
There is an inverted version that gets discussed less, and it applies to anyone paid to be the expert on someone else’s system.
Antonio Pagano wrote about the senior engineer’s trap for Wawandco: an architecture review where the facilitator kept finishing the other engineer’s sentences, adding boxes to the diagram, steering toward the answer he had already reached. The session found the real risks. The other engineer left compliant instead of sharper.
Put that beside the surrender research and it runs on a similar mechanism with the roles swapped. In one, a model hands you a complete answer and you stop building your own. In the other, you are the one handing over the complete answer, and someone else stops building theirs. Pagano frames it through scaffolding theory instead of borrowed confidence, so the parallel is loose. The outcome is not.
The team-level version has been studied. Alami, Zahedi and Krancher’s Antecedents of psychological safety in agile software development teams (Information and Software Technology, 2023) ran eighteen interviews and then surveyed 365 practitioners to find out what produces the conditions where people say the awkward thing. The answers were behavioural: openness, absence of blame, collective decision-making inside the team, and leadership taking ownership of the climate.
The result I did not expect is a negative one. Team autonomy, slack time and technical practices providing a safety net were not found to promote psychological safety. That is a non-significant result on a survey rather than proof of no effect, so read it as an absence of evidence. But it is an uncomfortable absence, because the safety net is the thing most teams reach for first, and because Pagano’s own post cites a separate study finding that autonomy does increase psychological safety. The literature is not settled and I am not going to pretend otherwise from an adjacent field.
One caveat on my use of it. That paper studies teams, and the thing I am describing is often one person deciding whether to admit to themselves that they have not formed a view. There is no interpersonal risk in that, so it is not psychological safety in the measured sense. I am borrowing the shape of a finding, not its authority.
What I take from all three is narrower than any of them: the conditions under which somebody admits they do not understand something are made by behaviour, and tooling does not appear to be sufficient. Which is inconvenient, because tooling is what everyone would prefer the answer to be. Myself included, since a checklist is a thing I can ship and a climate is not.
How to review AI-generated billing code
The habits below are Osmani’s, from the posts linked at the top. I am reproducing them because they work, not because I improved them. One is mine and I have marked it.
-
Write down what you expect before you read the answer. Two lines: what you think is wrong, and roughly what the fix should look like. If the answer matches, you are calibrated. If it does not, you have a decision to make instead of a plausible paragraph to accept. This is the one I skip most often when tired, which is exactly when it matters.
-
Read the diff as though a competent stranger submitted it. Would you merge this on the strength of a green build? You would not. The standard does not change because the author is a model.
-
Record the why at the moment you decide it. A minute at the time, unrecoverable later. The guard clause with no reason attached is the most expensive artefact in a legacy codebase, because the next reader, human or agent, will delete it confidently and be right about the code and wrong about the system.
-
Build something small without assistance now and then. Not on principle, as a measurement. There is no other way to find out how much you have quietly stopped being able to do.
-
Ask what happens on the second delivery. This one is mine, and it is the only thing in this post that is. Apply it to every change that touches money. It is narrow enough to ask every time, and it covers a large share of what I have seen go wrong in this kind of code.
That is four borrowed and one added, which is roughly the ratio this whole post runs at. I would rather say so than let the framing imply otherwise.
Where this does not apply
Most of what I write gets none of this.
Scaffolding, one-off scripts, admin screens, test fixtures, a migration for a reporting table. Delegate all of it and do not feel virtuous about reviewing it line by line. The cost of not understanding a throwaway script is that you throw it away.
There is a tension here with something else I believe. I have argued that boring, legible code is worth defending everywhere, and that a competent stranger should be able to change any part of a system without archaeology. That still holds, and the two are reconcilable only if you separate them. Write everything legibly. Spend the expensive kind of attention, the slow adversarial what-if-this-runs-twice kind, unevenly.
Understanding is finite. The mistake is not offloading. It is offloading at the same rate in the directory that issues refunds as in the directory that renders a settings page.
The research on cognitive debt is getting better and the general advice attached to it is fine as far as it goes. What it skips is that the interest rate varies enormously by what the code does. Somewhere in your system is a path where not understanding something costs a customer money today instead of costing you an afternoon next quarter, and that path deserves a different standard. The standard is not to think harder. It is a small number of questions asked every single time.
Somebody has to be able to reconstruct the money path from first principles. If that is nobody, the tools did not cause the problem, but they made it a great deal easier to arrive at.
FAQ
Offloading is handing over the work while keeping the judgement, so you still form your own view and can override the output. Surrender is when you stop forming an independent view at all, so there is nothing left to check against. The distinction is from Steven Shaw and Gideon Nave’s Wharton paper on AI and reasoning, and Addy Osmani’s cognitive surrender is the clearest explanation of it for engineers.
On unfamiliar material the evidence points that way. Anthropic’s randomised trial reported that engineers learning a new Python library with an assistant scored around 50% on a comprehension quiz against roughly 67% for those working by hand, with the largest gap on debugging, and close to no speed advantage. Within the assisted group, the people who used the model to build comprehension scored well, whether they asked only conceptual questions or generated code and then asked for an explanation. The worst scores went to those who generated and moved on. That within-group comparison is observational and involves very few participants, so treat it as a direction and not a law.
Because revenue failures are quiet and immediate. A broken page raises an error somebody sees; a renewal that fails to extend an expiry reports success. The debt is charged as a wrong payment to a real customer instead of as a slower refactor two quarters out.
The goals, constraints and rationale behind a system that were never written down outside somebody’s head. The term is Margaret-Anne Storey’s, from her triple debt model, which separates it from technical debt in the code and cognitive debt in a team’s shared understanding. It is the only one of the three an agent cannot repay: asked why a guard clause exists, a model will produce a confident answer whether or not it knows.
Write down what you expect the change to look like before you read it. Read the diff as though a competent stranger submitted it and you had to defend merging it. Record the reason for anything defensive next to the code, so the next reader does not delete it. And ask what the change does if it runs twice, because with at-least-once delivery that is normal operation and not an edge case.
Not on its own, as far as the evidence goes. Alami, Zahedi and Krancher’s study of psychological safety in agile teams found openness, absence of blame, collective decision-making and leadership ownership produced it, while team autonomy, slack time and technical practices providing a safety net did not reach significance. That is an absence of evidence and not proof of no effect, and other work disagrees about autonomy. Treat it as a caution against assuming a safety net is sufficient.
Try to reconstruct a recent design decision without opening the code or the agent. If you can say why it was made and what it was defending against, you offloaded. If you can only say it seemed reasonable at the time, you did not.