Before you delete the duplicate code your AI wrote

I spent a cleanup afternoon a while back deleting things that looked redundant in a vibe coded app, and one of them took the whole page's scroll down with it.

It was a smooth-scroll setup. Two calls sat right next to each other doing what looked like the same job, and every instinct I had said the second one was copy-paste the AI had left behind. So I cut it. The diff looked clean, the tests stayed green, and scrolling died on the deployed site. Not locally, where I had a warm reload and everything worked. On the deploy, on the exact path I hadn't thought to test.

If you're a vibe coder cleaning up AI-generated code and you want the short version: don't delete a duplicate because it looks like one, delete it because you measured that it does nothing. The answer to "my AI wrote duplicate code and removing it broke everything" is almost always the same underneath. Text that looks identical is not behavior that's identical. Some of what reads as redundancy is load-bearing resilience, a second call or a guard that only earns its keep on a timing or an edge case you won't hit until production does. Surface signals get to propose a deletion. Only semantic measurement gets to carry it out.

why did deleting the duplicate break everything?

The receipt: that second scroll call wasn't a duplicate, it was insurance against a race. The scroll setup initialized against a ref that, depending on how a provider mounted, wasn't reliably ready on the first call. Sometimes the first call bound to nothing. The second call, the "redundant" one, caught the case where the ref had landed by the time it ran. On my machine, with warm state, the first call always won and the second genuinely looked pointless. In production, with a cold mount and different timing, the first call missed and the second was the only thing making scroll work at all.

That's the whole trap in one sentence. The duplication was real at the level of text and false at the level of behavior. A grep saw two identical calls. The running app saw a primary and a fallback. I had trusted the surface signal, the thing that's cheap to see, and skipped the semantic one, the thing you have to actually run to observe. The principle I keep relearning is that surface signals are allowed to propose and only measurement is allowed to dispose, and cleanup is where that rule earns its keep.

how do you tell resilience from redundancy?

You diff behavior, not text. Before you cut something that looks duplicated, the question isn't "does this match the other one," it's "what changes on every path if I remove it." That means you actually have to know the paths. A call that's genuinely redundant produces the same result whether it runs once or twice. A call that's load-bearing changes the result on some path, usually a slow one, a cold one, a second-render one, the kind a local test with warm state never exercises.

Three moves make this safe when you're cleaning up a vibe coded codebase. Delete one thing at a time, never a batch, so when something breaks the blast radius is a single change and you know exactly which one did it. Reproduce on the path you don't normally hit before you decide: cold load, real device, the deployed environment, not just the happy local reload. And when you can't tell whether a duplicate is resilience or redundancy, leave it and label it, because a one-line comment explaining why it's there beats a clean-looking delete that quietly removes a guard nobody documented.

the feed says delete the slop

There's a story going around this week about a team charging five figures a week to delete AI-generated code from companies drowning in it. The data underneath it is real. One widely-shared analysis found duplicated code blocks up more than 80% since 2023, with refactoring falling off a cliff as people copy-paste from their AI instead of consolidating. So the instinct is right that vibe coding accumulates duplication, and plenty of it genuinely is dead weight worth removing.

The move the discourse skips is the measurement step. "Mass-delete the duplicates" is a surface operation on a semantic problem. Most of that duplication probably is slop. Some of it is the only reason the app survives a race you've never watched fail. The difference between the two is invisible to a grep and invisible to a glance, and it's exactly the difference that decides whether your cleanup is a win or a Monday outage. The work was never deleting duplication. The work is measuring which duplication is holding the app up before you touch any of it. That's the same discipline whether you're auditing before you ship or deciding what's safe to cut. I wrote up the first half in how to audit AI-generated code before you ship, and the case against reflexive rebuilds in fix the AI-generated app before you rebuild it.

If you've inherited a vibe coded codebase that's clearly bloated and you want a second set of eyes before you start cutting into it, so the cleanup doesn't take a load-bearing guard down along with the actual slop, /work-with-us. Most of what a safe cleanup is comes down to measuring behavior before you trust the diff.

None of this makes the work slower in the way that counts. It makes it one-change-at-a-time instead of one-big-delete, which feels slower and is really just the gap between a cleanup you can trust and a cleanup you have to roll back on Monday. The duplicate that looks dumbest is occasionally the one keeping the lights on. Measure first, then cut.

// part of the custom apps topic

// grab the free starter kit that makes your AI stop forgetting and stop guessing: get it →

// building with AI? the field manual has the structured lessons.

// hitting this on a real build? this is what I fix →