Drift at machine speed

A dense illustrated city of clashing architectural styles — a Gothic cathedral, Soviet concrete blocks, a Japanese house, an Islamic arch, a classical temple, and favela shacks — all accreted around one giant tree trunk, with construction cranes still bolting on more and airships drifting overhead.

One structure, grown by accretion: a Gothic nave, a Soviet block, a temple, a shophouse, and a favela, all bolted onto the same overloaded trunk while the cranes keep adding more. Every piece fit locally. Nobody was watching the whole.

The software development loop used to have a natural clock speed: a person reads an issue, writes the change, opens a pull request, waits for a review, merges. Days, sometimes hours. Every station ran at roughly human pace, so the whole thing stayed legible — you could hold the shape of what was changing in your head.

Coding agents broke that clock. Plan, write, run the tests, revise, open the PR — the parts a machine does now happen in minutes, and a single engineer can keep three or four of those loops bouncing at once. Throughput went up by an order of magnitude. One station did not speed up: the part where a human looks at the change and asks whether it still fits the architecture.

That mismatch is the whole problem.

The development loop: plan, code, and merge each take minutes, but architecture review still runs at human speed, making it the bottleneck the loop bounces off. plan minutes code + test minutes arch review human speed merge minutes next change starts before the last one was ever understood structurally

Every station in the loop got faster except the one that checks structure — so it becomes the station the loop bounces off, and most changes route around it.

The station that didn’t scale

A human reviewer reads a diff for the things a diff shows well: is the logic right, are the tests there, is the naming sane. What a diff shows badly is structure. “This PR adds one import from billing into auth” is not a line a reviewer flags, because on its own it isn’t wrong — it’s a single edge. Nobody is holding the whole dependency graph in their head while skimming the fortieth agent-authored PR of the afternoon, and structure is exactly the property you can only see by comparing the whole graph before and after.

This was already a problem at human speed. Architectural erosion has been shown to be a leading indicator of where bugs and churn land next — the components quietly accumulating cross-boundary dependencies are the same ones that go on to accumulate issues and painful refactors (Le et al., ICSA 2018, ICSA 2021; see Research). The usual defense was a yearly — or never — architecture review: block out a week, redraw the diagrams, write a report, watch the structure resume drifting the day the review ends.

At agent authorship rates, “yearly” isn’t slow, it’s fiction. Months of small shortcuts compound between two afternoons, let alone two annual reviews. You cannot close a machine-speed gap by asking a human to read faster.

Don’t review faster — change what triggers the check

The move is to stop treating structure as something a person audits occasionally, and make it something that gets checked automatically on every change, at the same speed the changes arrive.

Commit a snapshot of the actual, as-built architecture next to the code. Then, on every pull request, recover the architecture again and diff it against that committed baseline. A new cross-component edge, a moved entity, a component that merged or split — it shows up as a comment on the PR that introduced it, at the one moment it costs almost nothing to fix. The same edge found eight months and forty commits later, during a review, is an afternoon of archaeology just to reconstruct why it’s there.

In arcade-agent, this is two commands of the arcade-arch-diff script:

  • arcade-arch-diff --source . --update-baseline writes the current architecture to .arcade/baseline.json — a plain JSON file, versioned by git like anything else in the repo. A CI job runs it on every push to your default branch, so the baseline always reflects what actually merged.
  • arcade-arch-diff --source . recovers the PR’s architecture, diffs it against that baseline, and posts the result as a markdown comment.

No server, no account, nothing to sign up for. The full workflow is on the CI page, and this site runs it on its own every pull request — the live baseline and diffs are published at Self x-ray.

It’s a comment, not a gate

One deliberate choice matters here: arcade-arch-diff is informational. By default it never exits nonzero — it does not fail your build, and it does not block the merge.

That sounds backwards for a drift check, and it’s the right default. A structural diff is a judgment call: some new edges are erosion, and some are a legitimately new dependency that the design now wants. A hard gate that can’t tell those apart trains everyone to reflexively bypass it, and a check people route around protects nothing. The goal isn’t to stop the merge — it’s to put the structural change in front of a human at the exact moment it’s cheap to reason about, instead of discovering it in an outage months later. Teams that want a gate can still choose to make one; the tool’s job is to make drift visible on every PR, not to make that decision for you.

The review station is the bottleneck the loop bounces off. You don’t fix a bottleneck by asking the humans behind it to read faster — you attach a check that runs at the same speed as the thing it’s checking, and let the human spend their attention on the handful of structural changes that actually deserve it.


Next in this series: what architecture recovery says about a real agent framework. See the drift concept for the underlying idea, or start with the CI setup.