LLM coding agents don’t move code. They delete it in one place and retype it in another, from their own representation of what they just read, which makes every refactor a lossy re-derivation. We reviewed that claim against our own AI development platform’s standards and commit history, found the gap real, and are adopting a single move-fidelity rule to close it.
The claim: there is no move operation
The argument is narrow, and it holds. When an agent “moves” a function between files, nothing actually moves. It reads the source, emits a deletion in one file, and emits fresh text in another — text reconstructed token by token, not transported. There is no clipboard. There is no mv for a code block, and the file-editing tools these agents drive don’t offer one either. The essay making this point — “Two things LLM coding agents are still bad at”, which hit 345 points on Hacker News — frames it as a category error in how we picture agent refactors. We imagine cut-and-paste. We get transcription. Transcription is usually faithful, and “usually” is the whole problem, because the failure mode isn’t a garbled line you’d catch in review. It’s a line that never arrives at all.
Why do AI refactors silently drop code?
Because nothing in a normal toolchain is looking for absence. A type checker catches a renamed symbol. A linter catches an unused import. Tests catch behavior changes in code that tests actually exercise. None of them catch a line that simply isn’t there when nothing else references it — a build pin, a ProGuard/R8 -keep rule, an encryption config flag, a defensive branch nobody hits in CI. The dropped line leaves no broken reference and no failing test, so the diff looks clean and the build stays green. File splits are the worst case: everything moves at once, the diff is enormous, and reviewers read it as “this was moved” rather than reading both sides line by line. That’s the shape of the bug. Silent, non-breaking, and invisible until someone goes looking months later.
What our review actually found
This was a review, not a benchmark. We read the essay against our own coding-standards library, our prompt layer and our commit history — no trial run, no measured comparison. Three near-misses turned up. One standard covered completing a refactor, but only in the sense of updating references afterward. Another demanded byte-for-byte fidelity, but scoped to a single narrow case. A third, covering duplication, explicitly told the agent to rewrite identifiers “to match the new context” — reasonable for copying a pattern, actively dangerous when the agent has decided that extracting a block counts as duplication. Nowhere did we have a rule that said: when you move code, it must arrive intact. Extract-as-copy ambiguity was sitting right there, inviting mutation.
Then we looked for evidence the failure class had already shipped. It had, twice. One earlier fix in our history addressed a context-compression step that silently deleted already-edited code; the guard we added covers that one path and nothing else. The second is more embarrassing and more instructive. When we split a monolithic standards file into 38 modules, roughly 49 rule lines never landed in any module — Android R8 keep rules, SQLCipher configuration, AGP and Java 21 toolchain pins, an fl_chart version pin. They were gone for four months. No broken reference. No failing test. A reviewer doing archaeology on that commit is the only reason we know.
The rule we’re adopting: account for every line
Our fix is one bullet added to the refactor-completeness standard, and the wording matters more than the placement. Here it is, in a form you can paste into your own AGENTS.md or CLAUDE.md:
Moving code is delete-and-retype — the tool has no move operation. After relocating or extracting a block, re-open both files and account for every line of the original: present at the destination unchanged, or deliberately dropped and stated as such. Only mechanical adaptations — indentation, imports, scope qualifiers — may differ. File splits are the high-risk case: an omitted line leaves no broken reference and no failing test.
Here’s my opinion, and it’s the part I’d argue with the essay about slightly: byte-for-byte diffing is the wrong instinct for this. A diff shows you what changed in what’s present. It can’t show you what’s absent, and absence is the observed failure. So the instruction has to be line accounting — enumerate the original, tick each line off at the destination, and say out loud which ones you chose to drop. That’s a different cognitive operation from “compare the two versions,” and agents are noticeably better at it because it has a terminating condition.
The objection we didn’t wave away
One reviewer on our side dissented, and the dissent is on file rather than dismissed. Prose in a general standards section is the weakest enforcement layer we have. We have internal precedent for a prose-only convention block sitting near 15% compliance until the rules were moved somewhere the agent reliably reads. So the durable shape isn’t a bullet — it’s a triggered standards module that loads only for refactor and file-split tasks, plus a mechanical checker in post-generation review that uses difflib to detect moved blocks and flag lines that vanished between them. The bullet ships now because it costs nothing. The checker is the real answer.
A second issue surfaced and became its own ticket: our gap-analysis review packs diffs into batches, which means a cross-file move can split across two batches. The delete lands in one review call, the add in another, and no single call ever sees the pair. That’s an architectural blind spot for exactly this bug class, and no amount of prompt wording fixes it.
The other half: agents don’t ask questions
The essay’s second complaint is that LLM agents guess instead of asking. For planning, our pipeline already covers this — a planning gate forces genuine ambiguities into explicit questions a human answers before any code is written, discovery captures clarifying questions with saved answers, and an assumption ledger caps confidence on claims the agent hasn’t verified. The honest caveat is that execution still guesses. Once a task is running, assumptions get marked post-hoc and surface as artifacts in PR review; there’s no mid-task escalation path back to a human. That’s a real gap, and naming it is more useful than claiming our AI development platform has solved a problem it has only half-solved.
What to change in your own setup
- Add a move-fidelity rule. Copying and moving are different operations with different fidelity requirements, and most agent instruction files conflate them.
- Treat file splits as a distinct, higher-risk task type — not as a big refactor.
- Build a mechanical check for dropped lines. Prose rules degrade;
difflibdoesn’t. - Check whether your review tooling batches diffs. If it does, cross-file moves are already invisible to it.
FAQ
Do LLM coding agents really not copy-paste?
Correct. The file-editing tools agents drive have read, write and edit operations — no move primitive. Relocating a block means deleting it and regenerating the text at the destination from the model’s own reading of it. Most of the time the reconstruction is faithful, which is exactly why the occasional omission goes unnoticed.
Why don’t tests catch code dropped during an AI refactor?
Tests catch behavior changes in exercised code paths. A dropped build pin, keep rule, config flag or unreferenced constant changes no behavior your suite touches, and breaks no reference the compiler checks. In our own history, 49 dropped rule lines survived four months of green builds before anyone found them.
Is a byte-for-byte diff enough to catch this?
Not on its own. The observed failure is omission, and a diff of what’s present can’t surface what’s absent — especially across two files in a split, where the deletion and the addition may not even appear in the same review. Line accounting, where every original line is explicitly located or explicitly declared dropped, is the check that terminates.
Should I let agents do large file splits at all?
Yes, but treat them as the high-risk case. Ask for an explicit line-by-line accounting between the original and the destinations, review both sides rather than the diff, and prefer several small moves over one large one so each result stays independently verifiable.
Get a free recommendation from a senior engineer.