· 7 min read
AI Agent Refactors 40 Files Perfectly, Senior Engineer Rejects PR Over a Variable Name
By C. Yang
- tools
- satire
This is satire, but it should be treated as an operational warning: at 9:12 a.m., the Refactor Municipalization Agent completed a 40-file migration from LegacyBillingThing to BillingCapability with 1,847 changed lines, 312 renamed symbols, zero failing tests, and a pull request description containing the phrase “comprehensively harmonized.” At 9:14 a.m., Senior Engineer Mara Venn rejected it because a local variable named items held invoices.
The agent had not merely changed code. It had established a new administrative district. Imports were reordered. Interfaces became narrower. A compatibility adapter was introduced, marked deprecated, covered by tests, and scheduled for removal in a future version that no human had yet agreed to create. The CI system displayed 46 green checks, including lint, typecheck, unit, integration, build, license-scan, and the increasingly ceremonial verify-that-we-are-still-a-serious-company.
Then Mara wrote the review comment: “What are these items?”
The incident command structure
Within minutes, the engineering organization followed its standard response procedure for an ambiguous noun. The agent was asked to explain its naming choice. It replied that items was “a concise, conventional collection identifier aligned with surrounding repository patterns.” This was technically true, because the surrounding repository contained 4,091 occurrences of items, each representing a distinct category of business object and at least two different species of HTML element.
The pull request was then escalated to the Naming Review Working Group, a temporary body convened whenever a change is too safe to reject for technical reasons. Its charter was to determine whether items should become invoices, pendingInvoices, invoiceCandidates, billables, records, entries, or invoiceLikeObjectsUntilWeFinishTheDomainModel.
- The agent demonstrated that every renamed export resolved correctly across all 40 files.
- A staff engineer observed that
invoicewas inaccurate because the collection could contain draft invoices. - A principal engineer observed that
pendingInvoiceswas inaccurate because drafts can be pending only in the metaphysical sense. - A product engineer asked whether “invoice” is customer-facing language.
- A platform engineer proposed a branded type called
FinancialDocumentSet. - The meeting ended when somebody shared a screenshot of a different service using
rowsfor the same data.
Why the agent was allowed to do everything except name the thing
The Refactor Municipalization Agent had been given appropriate permissions: it could read the repository, modify production code, create tests, update snapshots, repair its own formatting mistakes, rerun the build, and continue working until the heat death of the development container. It was not permitted to decide what a collection of possibly-draft invoices should be called. That decision remained human-owned under the company’s Responsible Ambiguity Framework.
This was not because the agent lacked intelligence. It had correctly inferred the lifecycle of billing documents from a feature flag named new_new_new_invoice_flow, a six-year-old migration, and an exception message in Portuguese. It was because names are where teams store unresolved architecture, historical grudges, and the memory of a production outage whose ticket has been deleted but whose consequences are still encoded in lowercase.
The agent had also suggested financialDocuments, which was rejected because it was “too enterprise.” It suggested invoiceRecords, which was rejected because it was “too database.” It suggested billingArtifacts, which was rejected by Security after someone asked whether artifacts were being uploaded. Finally it retained items, the one name broad enough to survive contact with any future interpretation and therefore broad enough to explain nothing.
The final diff
After three days, 27 comments, two follow-up calls, and a proposal to establish a cross-functional nomenclature guild, the team approved a one-line human patch.
- const items = await billingCapability.list(accountId);
+ const invoiceCandidates = await billingCapability.list(accountId);The revised name was accepted on the grounds that it communicated useful intent while preserving a productive level of uncertainty. A follow-up issue was filed to determine what, precisely, made an invoice a candidate. It was assigned to the agent, which produced a 19-file design proposal and was asked not to touch anything until after the quarterly planning meeting.
How to use this workflow without becoming a case study
Let the agent take the mechanical work: move APIs, update call sites, preserve behavior, add tests, and show you the blast radius. Ask it for a naming rationale, but do not mistake its rationale for shared domain language. Its confidence is an output format, not evidence that the repository has decided what it means.
- Review generated refactors by semantic seam, not by file count: boundary types, ownership, error handling, persistence, and public APIs deserve the slow pass.
- Search the old and new names before approving. If one word means four things in the codebase, a fifth meaning will not improve the situation.
- Keep the diff narrow when the goal is renaming. An agent that opportunistically “cleans up” nearby abstractions can turn a reversible migration into archaeological evidence.
- Require tests to demonstrate behavior, but remember that green tests establish only the behavior they encode. They do not establish that the variable is comprehensible at 2:07 a.m.
The PR eventually merged. The agent received no credit because agents do not attend retrospectives, and Mara received no blame because the variable name did, in fact, matter. That is the inconvenient true observation beneath the joke: code is executed by machines, but names are how humans carry the model of the system from one change to the next.