Working software can still break its architecture
A change can compile, pass every test and follow the design for the part it touches, while the system as a whole stops having one answer to a question it should answer once. We call this drift, and it is the problem AG exists to solve.
Observed, not imagined
The patterns below come from a large private application developed over many months, mostly by AI coding agents working from written specifications. It had an architecture graph declaring owners, authorities and rules, and thousands of passing tests. Its architecture drifted anyway. Nothing failed: the drift surfaced only when a feature needed two parts of the system to agree, and they turned out to be separate implementations of the same responsibility.
Locally compliant, globally inconsistent
A test shows that a correct path exists. A declaration says which path is intended. Neither shows that the intended path is the only one, or that every entry point reaches it. Coding agents make the gap wider: an agent works toward a visible finish line, the feature works and the tests pass, and the shortest route there is often a wrapper, a copied piece of orchestration or a new registry. The agent can truthfully say its path works. Nothing asks whether it just created a second one.
Six patterns we saw
- Blended result
- One output assembled from several independent computations of the same thing, with none of them responsible for the answer.Seen: A report that looked like one result drew its figures from four separate passes over the same data. Each pass was tested. When they disagreed, nothing noticed.
- Shadow authority
- A secondary path that keeps a private copy of rules the system is meant to define once.Seen: A finer-grained variant of the central calculation lived in an experimentation harness with its own setup, selection rules and timing loop, and production had come to depend on it.
- Specifics in the platform
- Feature-specific logic pushed into a generic layer so that two paths can be made to look unified.Seen: The first attempt to merge those two variants put feature-specific logic into the generic reporting layer. It passed its tests and was rolled back in review.
- Copy-forward
- Supporting code duplicated into a new path instead of shared.Seen: The same attempt copied data-acquisition and chart code. Every copy worked, and every future fix would now be needed twice.
- Open registry
- A registry whose members are whatever code registers itself at runtime.Seen: Any module could add an execution capability through a public function, so a second implementation could appear without anyone editing the first.
- Permanent bridge
- A migration that adds wrappers so the new path works while the old one stays reachable.Seen: Switching to a new execution path directly would have needed new bridges, leaving both routes live with no point at which the old one was removed.
What did not work: proving everything
The project's first response was to prove every architectural claim: exhaustive enumeration of the code in scope, results bound to content hashes, adversarial tests, and gates that stopped all work until every claim passed. It worked for what it checked, and it consumed months with no features delivered. Existing drift had to be fixed before anything else could proceed, the proof machinery had to prove itself, and full validation took hours. The lesson was that most of these patterns can be caught by cheap structural checks, and that a check nobody can adopt prevents nothing.
How AG responds
Today, the graph records who owns each responsibility, which part is the authority for a shared meaning, and which rules must hold, and ag context puts those in front of an agent before it changes the code.
Planned, Architecture Audit will check the code against the graph's declarations: imports that cross a declared boundary in the wrong direction, modules reachable from an entry point that must not be, and a second implementation of a role that should have one. Existing violations go in a baseline that can only shrink, so new drift fails the pull request while old drift is tracked and paid down instead of blocking all other work.
Some problems no check replaces. Missing design work, behavioral bugs and values that look like verification but decide nothing still need tests and review. AG's claim is deliberately narrow: new structural drift gets caught, and existing drift stays visible.
Read the full account, including how each pattern was missed and which check addresses it.