№ 001engine PRs 204-2117 minTal Weiss
Our architecture map fails CI when it lies
Agents write most of our code. So we made the architecture map a build artifact: import drift fails CI, and stale prose goes red.
AI agents write most of the code at this company. Two repos, about 190,000 lines of TypeScript, and I have read maybe a tenth of it. For a while I felt bad about that in the abstract. Then it got concrete: I caught myself unable to answer basic questions about my own product. Which service actually publishes a post? Where does a render run? Is there a queue in there somewhere? I had a diagram from June. It had been wrong since July.
There is a name for this now, comprehension debt, and most writing about it lands on some version of "read the code before you merge it." Fair. But I run this company alone, with agents, and reading everything before merging is precisely the thing that does not scale. It is why the agents are here. So we went the other way around: if I am not going to hold the architecture in my head, the repository has to hold it, and it has to be mechanically impossible for that picture to go stale without anyone noticing.
This week we merged a run of six PRs that attempt exactly that. This note is what we built, what it costs, and what it has already caught.
A map nobody trusts is worse than no map
The planning doc for this run states the problem better than I can paraphrase, so:
Hand-written architecture diagrams rot silently, and a map nobody trusts is worse than no map: it is read once, found wrong, and never opened again.
Every team I know has that diagram. The interesting part is not drawing a better one, it is making rot loud.
The map itself is a LikeC4 model: ten plain-text files, about 2,100 lines, describing 205 boxes and 146 calls across six regions (people, this laptop, Google Cloud, AWS, third-party services, the social platforms). Each element declares which source files it stands for:
studioServer = service 'Studio HTTP engine' {
metadata {
sourcePath 'src/runtime/studio/studio-server.ts, ...'
deployedOn 'gcp-cloud-run'
cloudResource 'cloud-run:shapeless-engine'
proseVerified '14129fba69fe'
}
summary 'The front door for the site, behind Cloud Run IAM.'
}
That sourcePath line is not documentation. It is the hook every check below hangs off.
One command renders the whole thing into a single self-contained HTML file, no server, no network, in under a second. It zooms semantically: a box opens in place when its contents would be readable, and the relationship lines aggregate up so the zoomed-out view stays honest.


There are also six "path" views that answer the questions I kept failing to answer, as numbered traces over the map: how a post reaches a platform (12 steps), how an agent run works (16), where the money goes (11).

None of this is the interesting part either. A pretty map rots exactly as fast as an ugly one.
The drift gate
The claim side is read through LikeC4's own parser, the same code path the rendered map uses, so the gate can never disagree with the picture a human sees. The oracle side is dependency-cruiser over both repos: 1,120 files, roughly 3,800 real import edges, with the sibling repo's files prefixed so both codebases live in one namespace. Files are attributed to boxes by their declared sourcePath, and the two graphs are compared in both directions on every npm run check.
The two failure modes are deliberately not symmetric:
MISSING a real import between two mapped elements that the map draws nowhere.
The diagram lies by omission, which is the failure that makes a map
worthless. Fails the build unless it is in acknowledged-gaps.ts.
UNBACKED a modelled edge with no import behind it. Reported, never fatal: the
most important edges on this map are NOT imports (the site calls the
engine over HTTPS, the engine reaches the fleet through a Postgres
row), and a gate that demanded an import for each would delete exactly
the edges worth drawing.
The escape hatch is a ratchet, not a snooze button. The edges the map deliberately does not draw live in one file, each with a reason, and an entry that stops matching real code fails the build too, so the file cannot quietly become a graveyard.
The first full run produced 227 findings. 122 of them turned out to be the same non-finding restated, a bug in how containment was compared, which is worth admitting: the first thing a drift gate finds is bugs in the drift gate. After fixing that, 133 real undrawn edges remained, and triaging them found actual problems, quoting the PR: three lying descriptions, the site's whole cron layer undrawn, a live Cloud Tasks queue nobody had mapped, and one edge drawn backwards.
One class of gap survives as a permanent design finding: six adapter-to-adapter imports where shared ffmpeg helpers cross capability boundaries without a port between them. The map did not just document the architecture. It found the place where the architecture is wrong, and it will keep the count at six until we fix it, because a seventh fails CI.
Sentences rot too
The import gate cannot check prose. A box's summary is the part a machine cannot verify: the code moves, the sentence stays, and a confidently wrong paragraph is worse than no paragraph.
So every box's prose carries a stamp: a SHA-256 over the exact bytes of the files its sourcePath names, truncated to 12 hex chars, stored in the model. Any byte change under a box turns its prose stale, and a test goes red naming the boxes. Two details I like more than I probably should:
- Stamp lines are stripped before hashing, because the map's own directory is a declared
sourcePath, and writing a stamp would otherwise invalidate the stamp being written. A fixed point no hash can reach. - The re-attest command does the mechanical half and then says the honest half out loud, every run: the stamp does not claim the prose is right, it claims someone read the prose against these exact files. Re-stamping without re-reading is the one way to defeat it, which is why the command tells you so.
Ten minutes after the merge train landed, the stamp gate went red on four boxes whose code the merges had reordered. They got re-read and re-stamped; that was PR 211, four lines. As I write this, three more merges have landed and the gate is red again, twelve boxes this time. That is not the system failing. That is the system being the only participant in this company that never gets tired.
The bill is part of the map
A box that claims to run in a cloud names which resource it is, and a 23-row ledger is probed in both directions: every row must describe a live resource, and an inventory sweep across both cloud projects flags anything the ledger never heard of. Today: 24 billable resources, all claimed. The source comment explains why the inverse direction exists:
This is the direction that finds the thing nobody is looking for and everybody is paying for.
A continent full of unnamed rectangles is how an orphan VM runs for a month.
Guarding the agents, not the map
The same run added tripwires pointed at the agents themselves, because norms written in prose were being ignored. Agents kept rendering video locally (wrong fonts, wasted hours) instead of on our render fleet, so now a PreToolUse hook lexes every shell command they attempt and denies the shapes that are always wrong, with a reason naming the correct alternative. It matches invocation shape rather than substrings, so a grep that merely mentions the forbidden command passes, and it fails open: a broken guard must never be the thing that stops an agent working.
And because this company once had three different "run everything locally" launchers, each written by an agent that could not find the other two, there is now a build-failing test that enumerates every npm script and demands each appear on a generated index page with a one-line description. The index currently lists 141 runnable things. A command nobody can find is a command the next agent rebuilds.

The ledger
Cost: about 6,000 lines of tooling, 1,900 lines of tests, and 2,100 lines of model, to describe 190,000 lines of product. The full drift cruise takes 24 seconds; rendering the canvas takes 0.78.
What it does not do: the stamps prove reading happened, not understanding. The UNBACKED direction runs on trust plus a tag. Coverage is asserted at 75 percent of files, not 100, because a floor that high enough to be honest and low enough to not be gamed is worth more than a vanity number.
What I actually get: for the first time since the agents took over the typing, there is a picture of my product that I can open, zoom, and believe, not because anyone promises to maintain it, but because the build breaks when it lies. The agents get the same picture, which might matter more. The next agent that touches publishing does not reverse-engineer the flow from 609 files; it opens the map, reads a 12-step path, and sees which sentences were verified against which bytes.
Betting on agents to write the code and on yourself to understand it only works if understanding has infrastructure. This is ours so far. The gate is red right now, twelve boxes, waiting for someone to go read them.
ShapelessAI is an agentic social media team: it researches your market, then writes, designs, and publishes posts and short video to nine platforms. shapelessai.com
