The thesis

Nobody owns this code.
Something still has to know its shape.

The generation problem is solved. The comprehension problem is not, and it is now the whole job — but it does not yield to better maps alone. Some code cannot be understood at any price, and the reason is its shape.

What actually changed

For thirty years the expensive part of software was producing it. Every tool we built — editors, type systems, frameworks, package managers — attacked the cost of writing. That cost has collapsed. A competent model produces a working thousand-line change in the time it takes to describe it.

What did not collapse is everything downstream: reading the change, deciding it is safe, finding what it broke, knowing where it belongs. Those cost exactly what they did in 2015. The bottleneck did not disappear; it moved one station down the line, and it now has a much bigger queue in front of it.

This is not a complaint about generated code being bad. Most of it is fine. The problem is structural: code is now produced by a process that keeps no memory and holds no responsibility, and the humans on the other side inherit artifacts they did not write, in a codebase they no longer have time to learn.

Three things broke at once

Review became the constraint

A reviewer's throughput is bounded by reading speed and working memory, neither of which has improved. When the diff arrives with no author who can explain the intent — because the author was a sampling procedure — review degrades into style-checking. The questions that matter are structural: what else calls this, what does the new coupling do to the module, is this the third implementation of a helper that already exists twice. None of them can be answered from the diff.

Onboarding lost its shortcut

Learning an unfamiliar codebase always worked the same way: find the person who wrote it and ask. That shortcut is gone in two directions at once — the people who wrote it are thinner on the ground, and increasingly nobody wrote it. What is left is reading, and the quantity to read went up by an order of magnitude.

Ownership evaporated

A module used to carry an implicit index in someone's head: why it is shaped like this, what depends on it, which parts are load-bearing. That index was never in the repository. It was in a person. When code is generated, revised, and regenerated by processes that do not persist, there is no head holding the index — and the artifact has to carry its own structure or nobody has it.

Documentation is not the fix

The instinct is to write more of it. That instinct produced the wikis we all ignore. The failure mode is mechanical, not cultural: a hand-written description of a system is accurate the day it is written and decays with every commit after. Multiply the commit rate by ten — which is precisely what happened — and the half-life of a hand-written diagram approaches zero.

Anything that has to be kept in sync by discipline will not be kept in sync. The only artifact that survives this rate of change is one derived from the code itself, recomputed rather than maintained.

A map is necessary and not sufficient

This is the correction we owe the argument above. Everything so far says the model of the system went missing and should be recovered from the code. All true — and it quietly assumes that a recovered model is a usable one. Test that assumption on a real tangle and it fails. Draw a perfectly accurate, always-current graph of badly organised code and what you have is an accurate picture of a mess: hundreds of nodes, edges crossing every which way, no reading order, nothing to hold. The map is not wrong. It is unholdable.

The limit is not in the tooling, it is in the reader. Working memory holds a handful of things at once, so a structure is followable exactly when every step of the descent presents a handful of things — and the step below that does the same. Readers who can follow one graph and not another are not reacting to the size of the codebase. They are reacting to shape: whether the form survives being zoomed.

Which means comprehension has two halves, and only one of them is a display problem. The first is the structure is invisible — solved by deriving it and drawing it. The second is the structure is unholdable, and no renderer solves that, because the defect is in the code. It is fixed by moving files and edges, or it is not fixed.

So the same graph has to answer a second question. Not "is this hard to change?" — the complexity and coupling numbers have always answered that — but "can this be followed?", which is a question about how the files are organised rather than what is inside them. Mezzanine scores it as four tiers over the graph each folder actually draws, and the top tier is recursive: a folder cannot earn it while sitting on top of a mess. The ladder and its gates are here →

Why this got urgent rather than merely true

Structure has always decayed. What changed is the rate and the ratchet. Code now arrives from a process that optimises for the change compiling, not for the folder still being followable afterwards — and nothing in that loop pushes back. The helper goes where it is convenient. The import crosses the sibling boundary because that is what resolves. Each choice is locally reasonable, none is reviewed for shape, and the aggregate is a tangle arrived at faster than any team of humans could have produced one.

That is a ratchet because the cost lands on the next reader, human or model. An agent pointed at a tangled folder pays for it twice — once in the tokens spent reconstructing an order that is not there, and again in the quality of what it writes on top. Structure that degrades makes every subsequent pass more expensive, which is the definition of a debt that compounds. Measuring shape is how the loop gets closed: a deterministic number the writing process can be held to, rather than an adjective in a review comment.

What a map has to be

  • Derived, never authored. If keeping it true costs a human anything per change, it will be false within a month. The standing rule in Mezzanine: no feature may force authors to annotate or fill in detail by hand. Value comes from what the code already says.
  • Deterministic. Identical trees must produce byte-identical graphs. Otherwise every reported delta is contaminated by parser noise, and the tool cannot be used to judge a change.
  • Mid-altitude. Not the symbol — LSP has that. Not the prose overview — that is where staleness lives. The layer in between: entities, their relationships, and how a change propagates through them.
  • Legible to both consumers. A human needs it rendered — a graph they can drag, panels that follow the cursor. An agent needs it as compact ranked text with explicit truncation, because it pays by the token. Same graph, two renderings.
  • Able to judge its own subject. A map that only renders is a map that reports a tangle as faithfully as it reports a tree, and leaves the reader to notice the difference. If the shape of the code is what decides whether the map can be used, the tool has to have an opinion about the shape — stated as a named blocker and one next move, not as a grade.
  • Honest about its own error. A map that overstates its accuracy is worse than no map, because people act on it. If call resolution is 93.7% recall, the tool says so, and says what an empty result does and does not prove.

The one thing code cannot tell you

A derived graph knows everything about how the code is wired and nothing about what it is for. No parser will tell you that these four modules constitute "billing", or that the cron job is the fallback for a webhook that fails silently. That layer is genuinely authored, and it is the one place where writing something by hand is unavoidable.

Elevator is the smallest language we could design for it. The design constraint was the decay problem above: nothing is mandatory beyond a name, so the spec is built sketch-first — one line the day you learn an area exists, depth only on the branch you actually just worked on. Depth where the work happens is also depth that stays fresh. And the parts that can be checked mechanically are: broken references, code claimed twice, paths that no longer resolve, identifiers named in a description that no longer exist in the file it points at.

What this is not

  • Not a replacement for LSP. Go-to-definition is precise and pointwise and should stay that way. Mezzanine occupies the altitude above it.
  • Not a linter, and specific about why. Smells and shape tiers are ranked signals to look at, never gates to fail a build on. Mezzanine's tiers are Mezzanine's, and three separate decision records concede that its gates can be wrong about a specific folder — a tool may hand you a diagnosis you are free to disagree with, but it may not fail your build with one. So mezz check ships no rules of its own: every failure it can produce traces to a bar somebody in the checked repo wrote down, and min_shape: fractal is deliberately not a rule anyone can declare. The measurements are Mezzanine's; the threshold is yours to argue over.
  • Not a service. No account, no upload, no telemetry. The engine is a binary; the graph is built on your machine from your checkout, and stays there.
  • No paid tier. Every feature is in the AGPL build, and always is — the engine is dual-licensed, but the commercial terms remove the AGPL's obligations for organisations that cannot take them rather than unlocking anything. Nothing waits behind a paywall, because the licence gates no features.

The bet

If most code will be written by machines, then the durable, valuable artifact is not the code — it is an accurate, always-current model of what the code is: its entities, its dependencies, its risk surface, and the domain it serves. Humans need that model to review and to onboard. Agents need it to act without re-reading the world on every turn.

And the second half, which took longer to see: that model is only worth having if the thing it models can be held in a head. Volume is not what makes a codebase incomprehensible — plenty of large systems are perfectly navigable, and plenty of small ones are not. What decides it is whether the structure repeats: a few things at this level, a few things inside each of those, all the way down. Code that holds that shape stays understandable as it grows, and code that loses it becomes unreadable long before it becomes large.

Build the model once, derive it from source, give it to both readers — and measure whether the thing being modelled still has a shape worth reading.

The older version of the same problem

None of this is new, incidentally. Anyone onboarding onto a decade-old enterprise codebase has been living it for years: undocumented domain vocabulary, a stack nobody on the team chose, logic hiding in config files, and three projects to hold at once. Generated code did not create the problem; it removed the last excuse for not solving it.

What that looks like point by point →