Tests green, architecture worse: a deterministic gate for coding agents
My coding agents kept the tests green. The architecture still got worse. In the DATAMIMIC EE core the agents didn't break the build. They broke the structure. Utilities landed in whatever module was closest, not where they belonged. Code imported past the public interface of another component. And the one that hurt most: clients got imported in places that had no business touching them, above all…
Tests remained green while the architecture deteriorated. The coding agents did not break the build, but they did damage the structure. Utilities ended up in the nearest module, not where they belonged. Code was imported past another component's public interface, and clients were imported in places with no business touching them, especially in communication between data sources and tasks.
This issue had two aspects: an architecture change not declared and a change making code harder to analyze, leading to clean-looking reports despite reduced visibility into the program. The gate that couldn't detect architecture deterioration could not differentiate clean code from code it could no longer see. The issue arose because the EE core specification was built deterministically, with architecture decisions stored in ADRs and loaded into agent skills.
On small tasks, this worked, but on larger tasks and longer sessions, it failed. A model's blind spots changed with the seed and context size, and relying on an AGENTS.md or skill to judge the pull request only moved the problem up one level. A gate an agent could argue its way around was not a gate. Existing architecture tests like ArchUnit, import-linter, and dependency-cruiser checked if a snapshot of code followed a set of rules, but what was needed was a comparison: the accepted state against the candidate, the change against what the agent claimed it would do, and a hard stop when the evidence itself got worse.
The smallest case, Fixture A, was a single function that returned the sum of two handlers. Tests passed without any new forbidden imports, cycles, or private accesses. The gate only compared findings, and while the architecture might still be fine, the static analyzer could no longer prove it. A deterministic gate would reject an undeclared change by comparing the expected state with the actual state, ensuring that a two-resolved-call scenario became one unresolved-call scenario.
The gate checks include verifying the target architecture contract, ensuring the code obeys the contract, and confirming the change matched the declaration without regressions. An agent must commit an expectation of what it intends to change before submitting its implementation. If it submits after the fact, it is rejected, even if the code is clean.
This gate helps ensure that undeclared changes are caught, improving the overall architecture quality.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.