AI changed your code but you can't tell what it did: Architecture drift is the real cost
A very typical scenario: I had an Agent do what seemed like a small task, adding audit logging for order cancellation.
It changed more than a dozen files, and tests passed. I opened the diff, stared at it for twenty minutes, and in the end could only confirm one thing: It runs. But what it did to the system's structure, I couldn't say.
This isn't a one-off failure; it's an increasingly common state in AI programming:
Code diffs keep getting longer, architecture changes keep getting more hidden.
When a human changed code before, a review could reconstruct intent from file names and call relationships. Now an Agent changes a dozen files at once; each individual change looks reasonable, but taken together they might amount to a structural migration. What you see is a pile of line-level changes, not "the system went from A to B."
That's what I call architecture drift.
1. Code diffs don't show structure
A code diff answers "which lines changed." But what a person actually wants to know is:
- Did new modules appear?
- Are there new cross-layer dependencies?
- Did some entity move from the orders module to the payments module?
- Did the public API surface grow?
- Is this change a temporary patch or a long-term structure?
Line-level diffs are hard-pressed to answer these.
Take a small example. To let order cancellation write audit logs, an Agent might do three things:
- Directly import the audit module in the orders module;
- Place the audit entity under the orders module;
- Conveniently stuff the "send audit event" logic into the order service.
Every line runs, and tests might pass. But structurally, the orders module now has a direct dependency on the audit module, the audit entity is in the wrong place, and the order service's responsibility has grown.
The next time someone wants to reuse audit capability in another module, they find it's welded to orders; the time after that, someone wants to split a module and finds dependencies already tangled.
The AI isn't deliberately writing messily. It's making the most locally rational decision: whatever exists in the current file, use what's nearby. The problem is it has no stable global structure to reference, so each local optimum adds up to overall drift.
2. Architecture drift has three common forms
1. Dependency drift
orders was supposed to depend only on domain, but to save effort it directly depends on payment. The code runs, but the layering is pierced.
2. Boundary drift
One utility function is copied into three modules; an entity that should be internal is referenced across modules; a new module is never formally registered and exists only inside some directory.
3. Semantic drift
Module names haven't changed, but responsibilities have. orders starts handling notifications, notifications starts assembling order queries. The name is still the name, but the system is no longer that system.
These three kinds of drift share one trait: tests don't necessarily fail, and code review may not see it either.
3. Why prompts can't contain drift
We usually write in prompts:
Don't touch the payment module. Don't introduce new dependencies. Preserve the existing architecture.
These aren't useless, but they're soft constraints.
Once an Agent's context gets long, early constraints get diluted; when it hits a "by the way" call, it might decide changing is more reasonable; more often, it simply doesn't consider it "changing architecture" — it's just making the code pass.
Prompts can express intent, but they can't form checkable structural facts.
4. Jin's approach: turning structure into checkable facts
Jin has the project maintain a small two-layer architecture:
L0: systems, packages, modules, layering, external dependencies, constraints;L1: entities, positions, fields, methods, relationships inside each module.
When an Agent wants to change structure, it doesn't directly edit the formal architecture; instead it creates a proposal and edits a target snapshot. Validation checks references in the target architecture, public entities, and layering constraints; after application, drift checks compare against real code:
- Does the module path exist;
- Do entity positions and symbols actually exist;
- Are public entities registered;
- Do cross-layer dependencies violate constraints;
- Are there unregistered public symbols in the code.
Once validation passes, a human approves, and the target is written into the formal arch/.
This doesn't slow down the Agent; it makes "structural change" explicit instead of implicit:
- When it wants a new module, the proposal shows a new module;
- When it wants a dependency, the difference shows a dependency edge;
- When it wants to move an entity, the position change is flagged;
- When it writes an unregistered public symbol, the drift check warns.
A person doesn't need to guess structure from a dozen-file diff; they first check whether structure changed.
5. Drift checks aren't a silver bullet
To be clear: Jin's drift check is declarative, not a full compiler.
It can find:
- Declared files or symbols don't exist;
- Module paths don't exist;
- Unregistered public symbols in the code;
- Entity positions outside the module directory;
plannedentities already exist prematurely.
It cannot prove:
- Code implementation matches business intent;
- No performance issues;
- No security vulnerabilities;
- Test coverage is sufficient.
So it's not an "architecture correctness prover" or a replacement for code review. It solves a narrower but annoying problem: structural changes are invisible.
6. What I actually want is not a "faster AI"
I don't need the Agent to be faster. I need it, when changing structure, to leave something I can understand:
- What it was before;
- What it is after;
- Why it changed;
- Which modules and dependencies were touched;
- Did I approve this version.
That's also where I started with Jin. It's not about making AI write less code; it's about making sure that after it writes, a human can still explain what happened to the system.
Project address:
https://github.com/ZYF93/opencode-jin
v2.0.32-jin.1 downloads (macOS / Windows / Linux):
https://github.com/ZYF93/opencode-jin/releases/tag/v2.0.32-jin.1
Full Chinese guide:
https://github.com/ZYF93/opencode-jin/blob/dev/JIN.zh.md
Jin is a community fork of OpenCode, not an official OpenCode product. The project is still early; feedback is welcome.
Top 1 from juejin.cn, machine-translated. The original thread is authoritative.
Thanks for sharing