by Serguey Shinder
Our pricing screen lets a category manager change prices for a group of products in a chosen set of branches. It was built that way because a lot of our pricing is local. A branch near a competitor's new depot needs sharper prices on cement and plasterboard than a branch forty miles away, and head office needs to be able to do that without touching everyone else.
On a Friday afternoon in August 2025 one of our analysts set up a weekend promotion on decking for two branches in South Wales. She picked the products, picked the two branches, then changed the region filter at the top of the screen to check something. Changing the filter cleared the branch selection. She did not notice, set the price, and pressed apply. On Saturday morning three thousand four hundred decking and fencing lines were twenty per cent cheaper in all thirty eight of our branches, on the busiest weekend of the summer for that category.
The code underneath was short and looked tidy. It built the update from the screen's choices, and it only added a condition on branch when the list of branches had something in it. Somebody had written it that way years earlier so the same function could serve national price changes from head office: send no branches and you get all of them. It was a convenience for one caller, and it had quietly become the meaning of nothing for every caller.
What I keep returning to is that the system had no way to tell two completely different instructions apart. I want this everywhere. I want this nowhere, by accident. Both arrived as an empty list, and the code chose the reading that did the most damage, because that was the reading that had been convenient once.
When we searched, we found the same habit in nine other places. A credit hold that applied to every customer when the customer list was blank. A stock transfer report that showed every warehouse when you deselected them all, which was harmless, and a stock write off tool that did the same, which was not.
We changed the rule rather than the screen. Everything is now an explicit choice with its own value, chosen on purpose, and an empty selection is rejected by the service itself, not just by the page, so a script or a future screen cannot repeat the mistake. Every bulk change now shows how many rows it will touch before it runs, and anything above a few hundred asks a second person. The analyst saw that number the following week on a change of her own, said it looked wrong, and it was.
The weekend cost us a little over sixty thousand pounds in margin. The rule I took from it is simple to state. Nothing should never be allowed to mean everything.
– Serguey Asael Shinder
Leave a Reply