Hundreds of team records had disappeared from a customer’s league, and the first thing I opened was a folder full of old recovery scripts.
There was one for hockey, one for soccer, and one for baseball. Each was meant to put a customer’s league back together from an older copy of the data. At a glance, they looked like three sensible tools for three different sports. In reality, they were three versions of the same old idea, each changed a little over the years.
The first thing I reached for was that old folder of scripts. It could not be the answer to the real problem. It cost time because I had to stop and read three long files carefully before changing a line. The scripts were similar enough that I could not assume a fix in one belonged in the others, and different enough that I could not safely treat them as identical.
Then I found the problem they had in common.
When a league is rebuilt, the records have to be copied into a shared system that holds many customers’ data. Each game, score, and player detail has a number attached to it so the system knows what belongs with what. A primary key is the technical name for one of those labels. It is just a number that tells the system, “this is this particular game,” and not some other game with a similar name.
Those numbers cannot simply be copied over. The rebuilt league needs new numbers, because the old ones may already be in use. So the recovery process temporarily gave related records safe placeholder numbers, copied everything across, and then replaced each placeholder with the new real number.
That last replacement was where the old scripts went wrong.
Imagine three families putting labels on boxes in the same storage room. One family has a box marked 42. Another family also has a box marked 42. If you tell someone to replace every 42 with a new label, without first saying whose boxes they are touching, they can change the wrong family’s box.
That is what the scripts could do. They updated records with a matching old number, but did not first limit the change to the customer whose league was being restored. A small test with one team could look fine. A larger league, where many teams had been created around the same time and old numbers overlapped, could quietly reconnect one team’s games to the wrong records.
The first answer might have been to patch the hockey script, then patch the soccer script, then patch the baseball script. I did not want to leave that problem in place. Fixing three copies would have meant trusting that we had found every copy, every slightly changed version of the same mistake, and every future copy someone might make.
Instead, the three scripts became one recovery engine, 1,477 lines long. That is not a smaller file. By the usual measure of fewer lines, it is not a tidy win. But the sport-specific differences moved into a set of instructions. The engine can look at the backup, determine the sport, and use the right list of tables and score fields without becoming a separate copy of itself.
The important change was not that the code got shorter. The important change was that the repair now has one home. Every time the process replaces an old number with a new one, it also checks which customer owns the record. The recovery can no longer treat every matching old number in the whole shared system as if it belonged to the same league.
That one-home idea made another piece of work possible. The recovery engine has hand-written lists of the information it needs to copy. Those lists can fall behind when a new feature adds a new field. Missing one can mean leaving behind part of a customer’s data during a recovery.
Once there was one engine, I could build one check for it. The check reads the lists in the recovery file, compares them with a spreadsheet-style export of the live database, and points out what is missing. It has thousands of columns across hundreds of tables to compare. That would have been much harder with three drifting versions of the recovery process, each with its own list and its own history.
This is not only a software lesson. Plenty of ordinary work grows this way. Someone makes a good checklist for closing a job. Then another person copies it for a different customer. A third copy gets an extra step. Months later, an important safety check is added to one copy but not the others. What looked like flexibility becomes a hunt through three almost-matching pieces of paper when something goes wrong.
The dangerous part is not just the duplicate copies. It is the slow drift. Each copy gathers its own small changes until the differences look intentional, even when nobody can explain them. By the time you need to fix the shared mistake, you first have to figure out where it still lives.
That 1,477-line engine now carries a single rule everywhere it touches a number: check whose league owns the record before the placeholder gets replaced. The three old scripts never enforced that rule anywhere, which is the actual reason a customer’s teams could vanish in the first place, and it’s the reason the new coverage check can compare thousands of columns against one file instead of guessing which of three copies to trust.