But as any developer who has inherited a legacy codebase knows, lines of code added are often a liability rather than an asset. When I opened the pull requests, I found major architectural divergence.
Where the Agents Diverged from Idiomatic Code
While almost all the agents managed to render a UI that visually worked, their underlying architectural choices fell into a few classic patterns of technical debt.
I had placed extensive, highly detailed markdown documentation in the repository outlining coding standards, including explicit instructions to use react-hook-form and Zod for forms. Every single agent ignored those written instructions. They all defaulted to standard LLM training data patterns: tracking form inputs via manual useState strings and validating emails with fragile, copy-pasted regular expressions.
Yet all the models successfully built complex Effect-based GraphQL resolvers. Why? Because examples of those resolvers already existed in neighboring files. The core takeaway is that written documentation is far less important to an AI than the code it runs alongside. Models will ignore your markdown guidelines, but they will perfectly replicate the architectural patterns they see in nearby files.
2. Optimistic UI: Syncing Cache vs. “Faking It”
When a user updates a teammate’s role, the UI should ideally update instantly, rolling back only if the API call fails. I observed two radically different architectural patterns emerge here:
- The Right Way: My self, Claude Max, Claude AWS, and Kimi, used TanStack Query’s cache properly. We manipulated
onMutate, took a cache snapshot, updated via setQueryData, and handled the rollback on error. Claude Max even abstracted this into a highly clean, reusable useOptimisticMutation hook. - The Shortcuts: GPT, MiniMax, and Mistral bypassed the cache entirely, tracking the mutation state locally in the component. Worse, MiniMax and Mistral literally hardcoded
setTimeout(() => {}, 1000) blocks to simulate network latency instead of integrating with the actual promise lifecycle.
3. Type Drift and Schema Mismatches
With automated OpenAPI code generation, you should inherit types, not write them. I didn’t manually declare a single type that already existed in the schema. The agents, however, struggled with strict types:
- GPT manually re-declared
MemberRole and TeamMember types, but changed the data shapes, such as defining an ID as a string when the backend schema explicitly demanded a number. - Kimi introduced a silent runtime bug by declaring a user role as an all-caps string (
'ADMIN'), while the backend code generator expected PascalCase ('Admin').
Evaluating an AI agent solely on token cost misses the point. The metric that actually matters for engineering teams is Remediation Time: How long does it take a senior dev to refactor the agent’s code to meet production standards?
Assuming a standard engineering cost of $100/hour, I calculated the Total Cost of Ownership for each run. This includes the initial token costs, the time I spent nudging the agent, and the time required to rip out bad abstractions, like fake timeouts and manual state tracking.