Cognitive Debt: The Half of AI-Assisted Development That Doesn't Live in the Code
Your code is a complete record of what the system does. It carries no record of why. That half shows up on no dashboard, and it leaves when people do.
Part 2 of 2. Part 1 covered the debt that lands in the code, the half you can measure.
Someone asks why the system does something. Three engineers go and read the code to find out. The code tells them precisely what it does, and not one of them can say why it does it that way.
Nothing breaks that day. It breaks a quarter later, as an estimate that triples in a planning meeting, or a migration that stalls halfway through with everybody blaming the code.
That gap is the whole subject of this post. The code is a complete record of what a system does, and it carries no record of why it does it that way. Every scanner, linter, and dashboard you own reads the first one.
The second only ever lived in people. Part 1 was about the debt that lands in the code, which is the half you can measure. This is the half you discover at the moment you need it and find gone.
The symptoms are all in the people
Cognitive debt does not announce itself as slow code. It announces itself as a team that has stopped moving confidently through a system it owns.
The tells are behavioural. Every change in one area waits for the one person who was there when it was built, and then the module acquires a reputation, and the reputation is "don't touch that."
Meanwhile the diffs keep getting approved, because they look reasonable, which is not the same thing as someone knowing they are right.
Why generation drains the why
Peter Naur answered this in 1985, in an essay called Programming as Theory Building.
His argument: programming is not the production of program text. It is the activity by which a team forms a theory of the system, what it does, why it is shaped this way, which constraints hold and which are incidental. The code is an inscription of that theory, necessary and lossy.
"Lossy" is the word doing the work. The theory cannot be rebuilt completely from the code and the documentation alone, without the people who built it, because the text is a compressed export and the compression discards the reasoning.
What has changed since is the byproduct. Writing code by hand was slow and effortful, and forming the theory was the side effect of that effort, because you could not implement a rule without first deciding what the rule was.
Generation removes the effort, and the side effect goes with it. The inscription now arrives without anyone having formed the theory it is supposed to be an inscription of.
Which leaves two clocks running at different speeds. Code arrives at machine speed, and a theory forms at conversation speed, because it needs somebody to decide something, say it out loud, and be argued with. That gap widens every sprint, and it is why this debt outruns the kind you can scan for.
Code arrives at machine speed. A theory forms at conversation speed. That gap widens every sprint.
Approving a diff is not understanding a system
Part 1 argued that review cannot save you from a generation problem, because it sits downstream of the mistake. Cognitive debt defeats it for a second reason. A good reviewer confirms that this diff is correct, safe, and consistent with the code around it, and none of that requires a model of why the system is shaped the way it is.
You can approve every change correctly for a year and hold no theory at the end of it.
The pattern we notice most on our own bench is that the two ways of working with an agent are indistinguishable in the output. One engineer uses the model to interrogate a problem: what breaks, what the alternatives were, why this boundary and not that one. Another uses the model to skip the problem.
The first comes away holding a model of the system, the second comes away holding a merged pull request, and the diffs look identical. The difference surfaces months later, in who can still explain the thing.
Why nothing in your toolchain finds it
Technical debt is a property of an artefact, so it can be inspected. A duplication report, a churn number, a security scan. Cognitive debt is a property of your team, and there is nothing to point a scanner at.
Worse, the dashboards are not merely silent, they are reassuring. Coverage holds, the suite is green, throughput is up.
Almost-right code does all of that. It passes review, turns the suite green, and fails later, at the moment somebody has to reason about the system in order to change it.
Margaret-Anne Storey named this gap in 2026 and placed it in a three-part model of software health: technical debt in code, cognitive debt in people, and intent debt in what gets written down. Cognitive debt in her framing is team-level, the erosion of shared understanding to the point where the team can no longer change the system safely.
The example she started from was a student team that stalled in week seven and blamed messy code, when nobody could explain their own design decisions. Even when the agents produce readable code, she writes, "the humans involved may have simply lost the plot."
So it reads as zero on every dashboard until the day the demand exceeds the understanding. The estimate that triples and the migration that stalls are not the debt arriving. They are the debt being called in.
What is in your code, and what was never in it
The code your team generated last quarter and the system you inherited from 2014 are the same problem at different ages, which is why one discipline covers both. This is also where the fix usually goes wrong, because "write more documentation" is the obvious answer and the wrong one. It pays to be precise about which parts of understanding are recoverable and which are not.
Behaviour is in the code, and a machine can get it out.
Every rule the system actually applies is in there: the conditions, the calculations, the thresholds, the validations, the edge cases and the exception paths.
The code is also the most reliable witness available, because it is what ran in production for the last twelve years. Specifications drift. The executed path does not.
This is what our Business Rule Extractor does. It reads a legacy codebase, identifies the rules and edge cases, and maps each one back to where it lives in the source, with our engineers validating the output before it reaches you. What you get back is a readable specification of what your system actually does.
The shared model is not recoverable by any tool, but the price of building one drops sharply.
A mental model still has to form in human heads, and that part has not changed since Naur. What changes is the raw material: a validated inventory of a few hundred traceable rules builds a model far faster than four hundred thousand lines of VB.NET.
Intent was never in the code at all.
Which of those rules is deliberate policy and which is a workaround for a vendor bug in 2009, which threshold is regulatory and which is somebody's guess nobody revisited, what was considered and rejected and why.
None of that is weakness in the extraction. The information was never written into the code, so there is nothing there to read.
That is the honest limit on our own accelerator. Extraction hands you a faithful map of what the system does, and it will faithfully preserve every rule that was a mistake. It cannot tell you which of those rules deserves to survive a migration, because that judgment needs intent.
What it does is put the judgment within reach. Nobody can rule on a codebase, and a business can rule on a list of named rules, one at a time.
How we go after the why
That limit is not a place to stop. When we take over a system somebody else built, recovering the why is a real part of the work, and it is mostly conversation rather than tooling.
We talk to whoever is still around: the engineers who maintained it, the people who supported it, the analyst who wrote the rules the code implements, the manager who asked for the exception three years ago. The questions are narrow and specific. Why is this rule in the system, what were you working around when you added it, which of these numbers came from a regulation and which came from a meeting.
We also go back further than the current version, to what the application was originally built to do. A surprising amount of a legacy system's shape answers a question nobody asks anymore: a constraint from a platform that got retired, an integration with a partner who left, a workflow built around a team that has since been reorganised. Knowing what the first version was for explains structure that looks arbitrary when you only read the code.
What we do not claim is that we come back with all of it. Some of it left with the people who left, and no interview recovers a decision nobody remembers making. What we commit to is going after all of it, writing down what we get with the reasoning attached, and being explicit about what we could not answer.
The original why has a shelf life
There is a second reason the original reasoning is often missing, and it is not loss. Sometimes the reason expired.
Applications change, the people around them change, and companies reorganise, get acquired, enter markets they were not in, and stop selling things they used to sell. A rule that was exactly right in 2014 can be a residue of a partner relationship that ended or a priority the business no longer holds. Recovering that original reason tells you why the code is shaped the way it is, not whether it should stay that way.
So intent is not purely a historical fact waiting to be dug up. Part of it is a decision available to you now, and a team that cannot find the original reason can still establish an operative one: this is what this rule is for, as of today, because this is what the business needs it to do.
Nobody is going to change this code in 2014. Every change from now on is governed by the reason you set now, which makes the operative why the one that decides how the system evolves.
Two things keep this from turning into fiction.
- 1Establish what a rule touches before you redefine it. Declaring that a threshold is policy going forward is always possible. Knowing whether the old value was holding up a downstream report, a partner's integration, an audit trail, or a regulator's expectation is a different job, and it comes first. Some rules were never yours to redefine at all: if a threshold came from a regulation, the current roadmap does not get a vote.
- 2A decided reason needs a name and a date on it. Engineering assigning a rationale to a pricing or eligibility rule, without the person who owns that rule in the business, records a guess with more confidence than the original ever had.
The practice: label where every reason came from
Both constraints collapse into one discipline, and it is the one we run on a takeover. Every rule in the comprehension memo, the one to three pages we write before touching an inherited system, carries the provenance of its reason in one of three states.
Somebody told us, or a document said so, and we can name the source. This is why the rule was built.
The original reason is gone or expired. A named owner has set what the rule is for, on a date, and the memo records the owner, the date, and the reasoning.
Nobody could explain it and nobody has decided yet. It stays in the system untouched, and it is marked as constrained until somebody establishes what depends on it.
The labels are what stop the exercise becoming retroactive invention. A memo that does not distinguish the three reads as though somebody knew, and a confidently written wrong reason is worse than a blank one, because it stops the next engineer asking the question.
They also hand you the number you did not have. Cognitive debt has no scanner, but the count of Unknown lines against the total is the first real gauge of how much of it your team is carrying. Watching that count fall over a quarter is a more honest measure of progress than any coverage figure.
If the discipline exists in-house, run it yourself, because none of this needs a vendor. What we get asked to do is the recovery job, on systems where nobody wrote any of it down, and maintaining a system you inherited is a different job from maintaining one you built.
Write the why down while you still know it
Reconstruction is the expensive version of all of this. The cheap version is writing the reasoning down at the moment somebody still holds it, which is what Storey's third debt, intent debt, is about: the rationale, goals, and constraints that guide how humans and agents evolve a system.
Note those last four words. The rationale is not only for your team, because an agent needs it for exactly the same reason a person does: neither can infer why a boundary exists from a file that does not say.
Two habits carry most of it. Neither applies to a prototype you will demo and delete, because debt only charges interest on systems that have to live.
- 1Write the why at the moment of the decision. Not in a wiki, not in a quarterly documentation push, not later. One line in the pull request or the design note, while someone still knows: "this threshold is regulatory, not tunable." That sentence takes a minute and it is complete. The reconstructed version takes a week of interviews and is not.
- 2Put the standing rules where both readers look. Part 1 made the case for rules files,
CLAUDE.mdfor Claude Code,.cursor/rulesfor Cursor, custom instructions for GitHub Copilot, as the way to stop an agent inventing its own architecture. They quietly do a second job, covered in what an AI agent needs to know before it edits an old codebase: the file that tells the agent which module owns what is the same file that tells your next hire why the boundary is there.
If the answer depends on a conversation with a specific person, that person is the artefact, and the artefact leaves when they do.
Every other debt is a chore. You pay down technical debt and get back the same feature you already had, only cleaner.
This one pays twice, because the rationale that keeps your team's shared model intact is the same artefact that widens what an agent can see. The memo that stops your team losing the plot is the context that stops the agent writing a fourth copy of a validator you already have.
The choice is when you pay, not whether
Every system that lives long enough ends up in the hands of people who were not in the room when it was designed. That is not a failure of anybody's process. It is what time does to a team.
From there it is the same job in two versions.
The reasoning was recorded while somebody still held it, and the next engineer reads it in an afternoon.
Nobody wrote it down, so it gets rebuilt from interviews and inference, and then decided fresh where reconstruction runs out.
We do the second version for a living. It works, and it is the expensive one.
Naur's point, forty years on, is that the program was never the text. Agents have made the export nearly instant while doing nothing whatsoever for the thing being exported.
The original reasoning has a shelf life, and some of yours is already gone. The operative reasoning is yours to set, this quarter, with a name and a date against it. There is only one position a team cannot recover from, and that is holding neither.
Taking over a system nobody left an explanation for?
We go after the why, write down what we recover, and name what we could not answer.
How we engineer AI-assisted developmentAnAr Solutions engineers AI-assisted software delivery for product teams, and takes over systems other people built. The memo, the interviews, the provenance labels, and the extractor above are what we run on real inherited codebases, as part of our AI-assisted development practice.








