---
title: "When the Delete Button Asked the Wrong Question"
canonical: https://dxdev.com/blog/2026-02-26_delete-button-asked-the-wrong-question/
datePublished: 2026-02-26
---
A complaint arrived: trial accounts could not delete their own sites. I read it as a problem with a delete button. It turned out to be a problem with a number that looked sensible but answered the wrong question.

The site in question belonged to a sports organization. Think of it like a family tree with three shelves. The whole site sat at the top. Leagues or seasons sat beneath it. Teams sat beneath those. Someone could delete the whole site from an admin page, but not in every case. If the site was large enough, or if the customer had put enough money into it, the page was meant to stop the deletion and say, "Please contact support."

That basic idea made sense. Deleting a site could mean wiping out a year of rosters and schedules. A person should take a second look before that happens in some cases.

The first version tried to make that decision in the browser, meaning the page open on the customer’s computer. The page received an **org graph**, which is just a saved map of how the site, leagues or seasons, and teams were connected. Then it counted the teams itself.

It did this with 35 lines of code and three nested loops. One loop went through the site’s children. The next went through their children. The third went through those children. Whenever it found something called a team, it added one to the count.

Picture somebody trying to count all the apples in three crates by opening the first crate, then every smaller box inside it, then every bag inside those boxes. It can work if the packing arrangement never changes. But it is a fragile way to learn a fact that the stockroom already knows.

The page needed that count for one small decision: show the delete button, or show the contact-support message. It was doing all that counting even though the official system already kept the team total. Worse, its three-loop plan only knew about three levels. If the organization later gained a fourth level, the page could quietly count too few teams. Nothing had to crash for that to happen. The answer would simply drift away from reality.

That first approach did not work for the people who mattered in the complaint. It also cost a trial user an unnecessary support email and some patience. An empty evaluation site that should have been easy to remove was being treated like an account that needed a human conversation first.

The team count was not the only problem. The rule also looked at something called package value. That was the listed dollar value of the plan assigned to an account. The old page stopped a deletion if there were more than 20 teams, or if that package value was above 100.

Here is the important difference. A plan can have a price on it even when no money has been paid. The trial account had a plan with a value above that old cutoff, but it had paid nothing. The policy was supposed to protect sites where a customer had actually invested money. The code was instead asking what plan name was attached to the account.

Those are not the same question.

This was not a spelling mistake or a broken button. The page successfully found a number, compared it to a cutoff, and did exactly what it had been told to do. The trouble was that nobody had stopped to ask whether the number meant what the rule needed it to mean.

I fixed the situation by moving both facts to the server, the place where the official records live. Instead of making the page reconstruct the team count from a map, the system asked directly for the number of teams. Instead of using the nominal price of a plan, it added up transactions marked as paid.

The new rule became much easier to say out loud: require contact if there are more than 20 teams, or if more than a sum has actually been received. A trial account with zero paid dollars falls below the money cutoff. It can delete its own evaluation site, which was the intended result.

The page became simpler too. It no longer had to walk through the organization tree or compare several fields. It received one small yes-or-no label, `contactToDelete`. If the label was yes, it showed the support message. If the label was no, the deletion could proceed.

That is a modest change, but it matters because the people using the page do not see the hidden machinery. They see only whether a button does what it appears to do. When a rule gets in their way, the rule needs to be based on the real thing it claims to measure.

That is the whole fix: the delete button was never broken, and the three nested loops were never wrong about what they counted. They were answering a question, 20 teams or a package value over 100, that had nothing to do with whether anyone had paid. Once the server started summing actual paid transactions instead of reading a plan's sticker price, a trial account sitting at zero paid dollars finally cleared the cutoff it should have cleared from the start, and its empty site went away with a single click instead of a support ticket.
