Learn / Dev Notes /

Designing safe asset cleanup for tools you don't own the data for

March 2026 8 min read Design Tradeoffs
Design philosophy Tradeoffs Safety Trust

There's a category of tools where the normal rules of software reliability shift. Most software is correctable: you can retry the request, roll back the migration, restore the backup. The cost of a bug is measured in time and effort — annoying, recoverable.

Cleanup tools for creative projects — tools that can locate and delete files — don't always fit this model. The data they operate on wasn't created by the tool, isn't stored by the tool, and in many cases cannot be recreated by anyone if it's lost. That changes what "responsible default behaviour" means, and it changes it in ways that aren't obvious until something goes wrong.

The ownership problem

When you build a tool that modifies or deletes user data, you are operating on someone else's work. This is different from a tool that generates, transforms, or processes its own outputs.

A compiler that miscompiles code produces a broken binary. The user fixes the source and recompiles. The original source is intact. A cleanup tool that deletes a file you needed — an original illustration, a licensed sound effect, a character sprite that took forty hours to produce — cannot give that back. The tool was wrong. The loss is permanent.

This asymmetry between author and tool, between what the tool can verify and what the user actually knows, is the central design constraint. Every decision about how aggressively to act, how much to automate, and where to put friction traces back to it.

What the tool cannot know No scanner can determine whether a file is "unused" with perfect certainty. It can determine whether a file is referenced in the locations it scanned. Those are not the same thing. Assets can be loaded dynamically. They can be referenced in code paths the scanner didn't cover. They can be set aside intentionally for future use. They can be required by a tool or plugin that operates alongside the project. The scanner sees a slice of the truth. The user knows the rest.

Optimising for the wrong failure mode

A common frame for evaluating tools is to ask: "how often does it get it right?" A high accuracy rate makes an aggressive tool look safe. If 98% of flagged files are genuinely unnecessary, surely you can trust the tool to act on them.

This framing misses something. The 2% false positive rate is not evenly distributed across files that don't matter. In a Ren'Py project, the most likely false positives are precisely the files that are hardest to recover:

  • Engine-managed assets loaded by paths the scanner doesn't recognise.
  • Assets used in custom screen definitions or plugin integrations.
  • Files held in reserve for a scene in active development.
  • Original high-resolution source files that are technically "unused" but irreplaceable.

A 2% false positive rate on a project with 500 media files means 10 wrongly deleted files. Depending on which 10 they are, the damage ranges from trivial to significant. The tool's accuracy statistic tells you nothing useful about where in that distribution your specific files fall.

The two types of error and their costs

Every cleanup decision involves two possible errors:

  • False positive (Type I): classifying a needed file as unnecessary. The cost depends on recoverability — from trivial (re-export from source) to severe (original source not available).
  • False negative (Type II): classifying an unnecessary file as needed, leaving it in the project. The cost is leaving clutter behind — disk space, confusion, noise in search results.

In most software contexts, these costs are roughly comparable and the goal is to minimise both. For creative asset management, they are not comparable. A false positive in a destructive cleanup can be catastrophic. A false negative costs you nothing you didn't already have.

This asymmetry should drive tool design toward higher false negative tolerance — leave more behind if necessary — and very low false positive tolerance. The default should be cautious. The aggressive mode should be opt-in, not opt-out.

The irreversibility problem in practice Many indie developers and small studios don't use version control for raw assets. Binary files are large; Git workflows are optimised for text. Dedicated asset management is expensive and adds overhead. The practical reality is that for a significant portion of BranchPy's users, the system's recycle bin is the only fallback — and even that is not guaranteed after an OS-level delete.

Design decisions that follow from this

Once you accept that the cost of a false positive delete is potentially unbounded and the cost of a false negative is bounded and low, several design decisions become straightforward:

Never delete by default

No cleanup action should be the default outcome of any scan. The scan produces findings. Findings require review. Deletion requires explicit confirmation. These are three separate user decisions, not one.

Show what you're not sure about

Files the scanner can't fully evaluate shouldn't be silently excluded from results, but they also shouldn't be presented as equivalent to clearly-flagged candidates. BranchPy surfaces uncertainty explicitly — protected files are visible, with a reason, so users can make an informed decision about whether to investigate further.

Separation of classification from deletion

The code that decides what to show and the code that performs the deletion should be separate, and the deletion layer should independently validate the set it receives. This means a bug in the display layer — showing a file as selectable when it shouldn't be — cannot alone cause an irreversible operation. There's a gate that doesn't trust the layer above it.

Prefer reversible operations wherever possible

Hard deletion is the last resort, not the first option. Where feasible, moving files to a staging location before permanent removal gives users a recovery window without requiring a backup. This is a planned path for BranchPy — acknowledging that even a well-designed confirmation step is not a substitute for a recovery option.

The trust model Building trust with a cleanup tool is not the same as building trust with most other software. For a text editor or an analysis tool, trust accumulates through consistent correct results. For a tool that can permanently delete things, trust also depends on the user's belief that the tool will not surprise them in the direction that causes damage. Predictable conservatism is more valuable than occasional cleverness.

The tradeoff you're accepting

There is a real cost to conservative defaults: efficiency. A tool that requires manual review of every candidate, that never acts on its own, that surfaces uncertainty instead of resolving it, is slower to use than one that just cleans things up for you.

For BranchPy's use case — Ren'Py projects, often by solo developers, often without robust asset recovery pipelines — that tradeoff is correct. We are optimising for the outcome where a user never has to say the tool destroyed something they needed.

That's not a universal answer. For a production studio with full version control, asset DAM systems, and dedicated QA, an aggressive cleanup tool may be entirely appropriate. The right level of caution depends on the recovery capabilities of the user, not just the accuracy of the tool.

Summary

  • Cleanup tools operating on user-owned data face a unique constraint: they can cause irreversible harm to work they didn't create.
  • Accuracy statistics misrepresent risk when false positives are concentrated in high-value, hard-to-recover files.
  • The cost asymmetry between false positive deletes and false negative misses justifies deliberately conservative defaults.
  • Structural separation between classification, display, and deletion prevents single-point failures from causing irreversible operations.
  • Reversible intermediate states (quarantine, staging folders) are preferable to hard deletion wherever they add a recovery window without false confidence.
  • The right amount of caution scales with the user's recovery capabilities — which BranchPy defaults to assuming are limited.