← Donecraft, the book ← Donecraft for AI ← Problem library

Deep dive · Architecture and coupling drift

Coupling-aware coding for AI-generated software

Why changeability has to be treated as a primary quality attribute when the code arrives faster than anyone can review its dependencies.

Software quality is usually discussed in terms of correctness, performance and security. AI coding exposes a fourth attribute that has quietly become just as important: changeability — how safely and cheaply the system can still be modified after this change lands.

An AI agent can produce a change that is correct, fast and secure in isolation, and still make the system harder to change tomorrow. That damage is invisible at review time because it is not a property of the diff — it is a property of how the diff couples to everything around it.

Changeability as a primary quality attribute

Coupling is the degree to which one part of a system depends on the internal details, behaviour or existence of another. Low coupling means a component can change without forcing changes elsewhere. High coupling means a change ripples — sometimes to a component the person making the change never looked at.

Human developers build an intuition for where the ripples run. An AI agent, reasoning from the file or prompt in front of it, generally does not have that intuition, and it is not penalised for missing it: the change still compiles, still passes the test it wrote, and still looks locally reasonable. The cost shows up later, and by then it is distributed across the whole codebase rather than attributable to one commit.

The practical implication: if changeability isn’t evaluated explicitly, AI-assisted teams will keep shipping code that passes every check they have and still gets harder to change every week.

Five kinds of coupling

Not all coupling is equal, and not all of it is bad. Treating it as one undifferentiated risk makes it impossible to reason about. Donecraft distinguishes five kinds:

Operational coupling

Runtime

Two components depend on each other while running — shared infrastructure, a live call from one service to another, shared runtime state. A change to one can break the other only in production, under specific conditions.

Developmental coupling

Change surface

Two pieces of code tend to need editing together — shared files, a shared build, shared ownership. This is the coupling that determines how many places a single conceptual change actually has to touch.

Semantic coupling

Meaning

Two parts of the system share an understanding of what a concept means — a business rule, a definition of “valid,” a unit of measure. When that meaning changes in one place and not the other, both sides keep compiling while quietly disagreeing.

Functional coupling

Collaboration

Two components exist to jointly fulfil one piece of behaviour — a call chain, a workflow split across services. This coupling is often necessary and deliberate: it is how a system does anything at all.

Incidental coupling

Accidental

Two components depend on each other for no real reason — a copy-pasted helper, a shared utility reused for an unrelated purpose, an import taken because it was already there. This is the kind AI agents introduce most often, and the kind with no offsetting benefit.

Strong coupling belongs only around stable concepts

The goal is not zero coupling — a system with no coupling does nothing. The goal is matching the strength of a coupling to how stable the concept behind it is.

Stable concept
Core domain invariants, rules that rarely change, interfaces the whole system already relies on. Strong, direct coupling here is cheap to accept: the ripple radius is known and the concept isn’t going to move.
Volatile concept
New features, evolving requirements, early-stage or experimental modules — anything still being figured out, including most first-draft AI-generated code. Coupling here should stay loose: behind an interface, isolated, easy to unwind before it hardens into a dependency everyone else relies on.

Applied to AI coding specifically: a change an agent proposes against a stable, well-understood part of the system can be allowed to couple tightly, because the surrounding shape is known and reviewable. A change against something still volatile — a concept the team itself hasn’t settled on yet — should be kept loosely coupled almost by default, because neither the agent nor the reviewer can yet judge whether today’s interpretation will still be right next week.

How Donecraft applies this

Each outcome loop is given a controlled code surface — an explicit boundary of what an agent may touch. That boundary is chosen deliberately against concept stability: outcomes that touch stable, well-understood concepts can be scoped more broadly; outcomes that touch volatile or newly-introduced concepts are kept narrow and isolated until the concept proves itself stable.

Verification then checks integration separately from implementation, so a locally plausible change is still evaluated against its effect on the rest of the system before it is accepted — catching incidental and semantic coupling that a single agent, reasoning only about its own diff, has no way to see.

Built into OPIR

OPIR, Donecraft’s open-source project runtime, is where bounded code surfaces, independent verification and outcome-linked traceability are actually implemented — the mechanics that keep coupling matched to concept stability in practice, not just in principle.

View OPIR on Codeberg →
← Back to the full problem library