One Claude Code Tip a Day: Treat Deletions as High-Risk Edits
When Claude Code deletes code, slow the session down: ask what each removal proves, which runtime path depended on it, and what verification would catch a bad cleanup.
This post is part of the “One Claude Code Tip a Day” series — a daily guide to using Claude Code more effectively.
The real failure: the cleanup that quietly removes a safety net
Claude Code is usually praised for adding code quickly, but some of the riskiest sessions happen when it deletes code confidently. Picture a frontend bug fix in a subscription app. A pricing banner sometimes shows an old plan name after checkout. Claude reads the component, finds a confusing fallback branch, removes it, simplifies the props, and the local happy-path test passes. The diff looks cleaner. That is exactly why it deserves suspicion.
Today’s habit is simple: treat deletions as high-risk edits. Not forbidden, not scary, just higher proof than additions. A deleted line may be dead code, or it may be the only thing protecting a slow API response, an old customer plan, a mobile-only route, or a deployment environment you did not reproduce. Claude Code should not be allowed to call cleanup “obvious” until it can name the runtime path that no longer needs it.
Start by separating fix from cleanup
Before Claude edits, make it distinguish the bug fix from optional cleanup. Use a prompt like this:
`We need to fix the stale plan name in the subscription banner. Read the relevant files first. Do not delete code during the first patch unless the deletion is required for the fix. For any deletion you propose, state the old behavior, the evidence that it is unreachable or wrong, and the test or browser check that would fail if the deletion is unsafe.`
That prompt changes the shape of the session. Claude can still remove code, but it has to carry the burden of proof. If the first answer says “remove legacy fallback” without showing where legacy plans are migrated, ask it to stop. The right next move is not another patch; it is a read pass through the route loader, fixtures, analytics events, or deployment config that made the fallback exist in the first place.
Make git diff read deletions out loud
After the first patch, ask Claude to inspect the diff from the perspective of removed behavior, not just changed behavior:
`Show git diff. For every removed block, write one sentence starting with: “This deletion is safe because…”. Then list the exact command, test, log, or browser path that proves the sentence. If a deletion has no proof, mark it as cleanup debt and propose reverting that part while keeping the actual fix.`
This is more useful than a generic “review the diff” request. It forces Claude Code to explain negative space. A good answer might say: the deleted `planName ?? cachedPlanName` fallback is safe because the loader now always returns `displayName`, proven by `subscription-loader.test.ts` covering legacy and current plans. A weak answer says the fallback is redundant because TypeScript passes. TypeScript can prove a value has a type; it cannot prove the slow backend path never returns an empty string.
A realistic second-pass correction
Suppose the unit test passes, but a browser check in a staging account shows the banner blank for an old annual plan. Do not ask Claude to “fix staging” immediately. Use the failed verification to decide whether the deletion was the mistake:
`Staging shows a blank banner for an old annual plan. Re-read the diff and focus only on deleted code. Which deletion could explain this? Revert the smallest unsafe deletion, keep any proven fix, then add a test that captures this old-plan case before changing anything else.`
This second pass prevents the session from piling a new fallback on top of a bad cleanup. Claude may restore the cached fallback, then narrow the real fix to the loader mapping. Or it may discover that the fallback should stay deleted but the fixture is missing an old plan field. Either outcome is better than letting the model chase symptoms while the original deletion remains unexamined.
What to verify
Use three layers. First, static inspection: ask why the removed branch existed and where callers now get equivalent behavior. Second, focused tests: run the test that covers the old path, not only the new happy path. Third, live or preview checks when the deletion touches UI, auth, billing, migrations, feature flags, or deploy scripts. Deletions in these areas often fail outside the file where they look clean.
For cleanup-only work, make the standard even stricter. If the only benefit is fewer lines, require stronger evidence: references search, route coverage, fixtures for legacy data, and a git diff review that isolates cleanup from behavior changes. If Claude cannot prove the cleanup, leave a note and ship the smaller fix. Clean code that removes an untested safety net is not clean; it is undocumented risk.
Failure modes
The first failure mode is accepting “unused” based on one search. Dynamic imports, configuration keys, serialized JSON fields, and CSS class names often do not appear as obvious references. Ask Claude what kind of reference search would miss the code before believing it.
The second failure mode is mixing deletion-heavy cleanup with a bug fix. Reviewers cannot tell which removed line fixed the bug and which one merely looked old. Ask Claude to split the patch or revert cleanup until the fix is proven.
The third failure mode is letting prettier diffs outrank production evidence. A shorter component is not a safer component if staging, logs, or old fixtures say otherwise.
Rule of thumb
When Claude Code deletes code, make the deletion earn its place. Every removed block should have a reason, a proof command, and a failure signal that would catch a bad removal. Additions need review; deletions need a cross-examination.