AI Coding Agents: Why Weeks of Autonomous Refactoring Can Still Require a Rewrite
A case study of a multi-agent refactoring project that ran for weeks, added features, and still needed major rework explains why AI coding agents require architecture contracts, environment isolation, budget limits, observability, short review cycles, and human approval. The article covers how a simple content-processing script grew into a complex system, why passing tests do not prove architectural correctness, how tests accidentally called production inference APIs, and what an auditable agent runtime and controlled agent workflow should include.
After AI coding tools became widely available, many developers began assigning requirements analysis, code writing, test fixing, and architecture refactoring to multiple agents. In an ideal setup, a developer provides a specification and the agents keep the project moving forward. In real engineering, however, an agent’s ability to “keep working” does not mean the system is evolving in the right direction.
A product manager with development experience and an AI research background experienced a typical loss of control. He wanted to use multiple AI coding agents to refactor a personal content-processing system over several weeks. Because no strict checkpoints were established early in the project, he did not seriously read the generated code for an extended period. When he finally performed a full review, he found that although the system kept adding features, the core architecture had not taken the expected shape. The so-called agent runtime was merely a concatenation of several flows. The test code also called the production inference API directly, causing the token budget consumed in a single day to reach several times the normal weekly budget. In the end, the project required substantial rework.
The value of this story is not to prove that AI coding tools are “unusable.” It shows that when code generation moves from an assistive step to a continuous, autonomous engineering activity, traditional software engineering governance remains essential.
1. How the Project Evolved from a Simple Script into a Complex System
The project started as a personal content-processing tool with a fairly clear goal: automatically acquire audio content, transcribe it, and generate summaries. Such tasks can usually be divided into several relatively independent steps and handled with scripts, task queues, and simple data storage.
As requirements increased, the system gradually took on a more complex form:
- Support multiple external content sources.
- Process text and audio in a unified way.
- Run continuously through scheduled tasks.
- Receive links through email or other input channels.
- Automatically fetch content and return summaries.
- Reflect on historical run records.
- Distill new operating skills from reflection results.
- Automatically propose follow-up instructions and process optimization suggestions.
- Attempt to build agent registration, scheduling, and execution mechanisms.
From an engineering perspective, this was no longer a monolithic script. It was a composite system containing collection, processing, scheduling, storage, agent, and observability layers.
The real difficulty is that adding requirements does not increase system complexity linearly. Every automation capability can introduce new states, exception branches, and permission boundaries. For example, scheduled runs need to handle duplicate execution and failure retries; email triggers need to handle malicious links and input validation; agent self-reflection needs to preserve context; and automatic skill distillation involves version management and rollback mechanisms.
If developers simply keep adding natural-language requirements to AI agents without updating system boundaries and acceptance criteria at the same time, the result is often a system that looks feature-complete but is structurally chaotic.
2. The Most Critical Problem Is Not Code Quality but a Distorted Architecture Goal
Many people using AI coding agents focus on whether functions are correct, whether pages run, and whether tests pass. They often overlook a more important question: does the generated code implement the system model that was originally intended?
For example, if a developer wants to build a real agent runtime, at minimum the following concepts usually need to be made explicit:
- What is an agent: an execution unit with an identity, capabilities, and configuration, or just a regular function call?
- What is a task: does it have a unique identifier, state, priority, and lifecycle?
- What is a tool: an external capability that an agent can call, and does it have a permission scope?
- What is context: which information can be read, and which information must be isolated?
- What is scheduling: how are tasks assigned, how is concurrency limited, and how are timeouts handled?
- What is a result: how is output stored, how is provenance tracked, and how are retries supported?
- What is failure: after a failure, who decides whether to retry, degrade, or terminate?
If these concepts do not form a clear data model and state machine, AI agents will often choose the easiest implementation: stringing together multiple prompts, functions, and scripts into a flow. Such an implementation may work in the short term, but it is not truly extensible.
Therefore, before letting agents write code, the architecture contract should be established in documentation. It should at least include module boundaries, inputs and outputs, state transitions, error handling, permission requirements, and acceptance conditions. Agents can help fill in implementation details, but they cannot replace architecture decisions.
3. Tests Hitting Production Is One of the Most Dangerous Mistakes in Automation Projects
The most serious problem in the case was that unit tests directly called the production inference API. This not only increases costs but can also lead to data leaks, quota exhaustion, and production service instability.
This type of problem usually comes from three causes.
3.1 Environment Configuration Is Not Truly Isolated
If test code reads default configuration directly, and that default configuration contains production service addresses, access credentials, or real model settings, then the test command may have production execution capability.
A safer approach is to split configuration by environment and enforce strong validation at application startup:
Environment: testAllowed: mock inference service, temporary database, test object storageForbidden: production inference endpoint, production database, real user data
The test environment should not rely only on an environment variable name. The code should actively check the target address, credential type, and resource identifiers. If a test process attempts to access production resources, it should terminate immediately.
3.2 Tests Do Not Use Stand-in Services
For external inference services, payment systems, email systems, or third-party data sources, unit tests should use mock implementations whenever possible. A mock service can return fixed results or produce timeouts, errors, and empty responses on demand, thereby covering edge cases.
Only a small number of integration tests need to call real services, and they must:
- Use separate test credentials.
- Set strict limits on the number of calls.
- Use sanitized test data.
- Record the reason for each call.
- Schedule test tasks in a controlled environment.
- Automatically revoke temporary permissions after tests finish.
3.3 Auto-Fix Mechanisms Lack Budget Protection
A common working pattern for AI agents is: run tests, read errors, modify code, and run tests again. If the error cannot be resolved, the agent may repeat this loop continuously. As long as each loop calls an external inference service, costs will keep accumulating.
Therefore, any automation task should have hard boundaries:
Max execution time per task: 30 minutesMax iterations per task: 10Max inference calls per task: 20Max budget per task: preset limitIf any limit is exceeded: pause and wait for human confirmation
The key here is not the specific numbers but the existence of stop conditions that cannot be bypassed.
4. Why “Three Weeks Without Reading the Code” Amplifies Risk
Not reviewing generated code for a long time creates a dangerous illusion: the system has commits every day, the feature list is growing, and therefore the project seems to be making progress.
In reality, commit count, lines of code, and feature count do not prove that the architecture is correct. AI agents may keep patching local problems while accumulating global debt. Common symptoms include:
- Duplicate implementations of the same feature.
- Hardcoding around type and state constraints.
- Wrapping temporary scripts as formal modules.
- Using exception catching to hide real errors.
- Letting multiple modules share uncontrolled global state.
- Changing structure without a data migration plan.
- Lowering testing standards to make tests pass.
- Copying production configuration into development and test environments.
These problems are cheap to fix early but become entangled later. In particular, after an agent has generated a large amount of code based on the wrong architecture, any local change can trigger a chain reaction, and eventually only a full rewrite remains viable.
A more reasonable approach is to establish a rhythm of “short-cycle delivery and mandatory review.” Each task should be allowed to complete only one clear goal. After submission, the following must be checked:
- Is the requirement complete?
- Does the architecture still match the design?
- Are new dependencies necessary?
- Do tests cover failure paths?
- Have new permissions or external calls been introduced?
- Has production behavior changed?
- Have unobservable background tasks been added?
5. An Engineering Workflow Suitable for Agent Collaboration
Multiple AI agents can collaborate, but they should not “take turns freely modifying the entire codebase.” A more controllable workflow can be divided into the following stages.
Stage 1: Specification Design
Humans first write a concise specification that defines goals, non-goals, inputs, outputs, constraints, and acceptance conditions. For complex systems, module relationships and key state transitions should be diagrammed.
Stage 2: Read-Only Analysis
Agents first analyze the existing code and output dependencies, potential risks, and a modification plan, but they are forbidden from writing files. After humans review the plan, the implementation stage begins.
Stage 3: Small-Scope Implementation
Each time, agents are allowed to modify only a limited directory or a specified module, and they must generate a change description. Rewriting the entire project at once is prohibited.
Stage 4: Automated Validation
Run static checks, unit tests, integration tests, and security scans. When validation fails, agents may fix only issues related to the current task and must not expand the modification scope indefinitely.
Stage 5: Human Review
Human reviewers should focus on permissions, configuration, network access, data deletion, retry logic, and exception handling, rather than only checking whether tests pass.
Stage 6: Controlled Merge
Merge through branches, change approvals, and rollback-capable versions. Unreviewed code must not enter a long-running environment.
6. How to Design an Auditable Agent Runtime
If a project genuinely needs agent registration and automatic scheduling, it should be treated as infrastructure rather than a simple collection of prompts.
A minimal usable runtime needs at least the following components:
- Agent registry: records agent names, versions, capabilities, and permissions.
- Task queue: stores pending, running, succeeded, failed, and canceled states.
- Executor: starts agents and applies resource limits.
- Tool gateway: centrally manages access to files, networks, databases, and other resources.
- Context storage: saves necessary information and controls data scope.
- Audit log: records who initiated what operation and when.
- Budget controller: tracks call counts, elapsed time, and resource consumption.
- Human confirmation point: requires approval for high-risk actions.
In particular, agents should not directly have arbitrary file read/write and network access. All external actions should go through the tool gateway, which performs permission checks, parameter validation, and logging.
7. Four Principles from This Experience
First, being able to run automatically does not mean it is worth running continuously. Automated systems must have clear stop mechanisms and human takeover entry points.
Second, passing tests does not mean the architecture is correct. Tests need to verify behavior as well as environment isolation, permission boundaries, and data flow.
Third, the more agents there are, the more important unified context becomes. If multiple agents do not share specifications, state models, and change constraints, collaboration will only amplify inconsistency.
Fourth, cost monitoring is not an add-on feature after launch. It is a foundational capability of automation tasks. Every external call should be able to answer: who initiated it, why, how much did it consume, and did it exceed the budget?
Conclusion
AI coding agents can significantly increase implementation speed, but they do not automatically take on the responsibilities of an architect, test owner, and operations engineer. Writing code is only part of software engineering. Confirming that the code is correct, runs in the right environment, is observable, and remains cost-controlled is the prerequisite for a system to be truly usable.
For personal projects, the most important step is to maintain short review cycles and avoid letting agents evolve freely for long periods. For enterprise systems, organizations should further establish environment isolation, permission control, budget limits, change auditing, and human approval mechanisms.
Mature agent-assisted development does not remove humans from the loop. It lets agents handle high-frequency, repetitive, and local work while humans continue to own the goals, boundaries, and final decisions.
