The migration that stalled at 90% — and the one table nobody owned
Every stalled migration has the same shape. The easy 90% goes fast, everyone celebrates the burndown chart, and then the last 10% sits there for six months. This one was no different — except the last 10% was a single table.
The table had no owner. Three services wrote to it, two teams each assumed the other maintained it, and the person who created it left in 2021. Nobody could say what half the columns meant, so nobody would sign off on moving it.
The call that mattered
The instinct was to reverse-engineer every column before touching anything. That’s the safe-looking choice, and it’s why the project had been stuck for two quarters. We made the opposite call: instrument the table for two weeks, find out what actually reads it, and treat everything unread as dead.
Two-thirds of the columns had no readers. Of the rest, one consumer mattered — a billing job that ran monthly. We didn’t migrate a table. We migrated one job’s input.
The trade-off nobody saw
Deleting the unread columns meant accepting a small, explicit risk — some once-a-year process might notice. We wrote that risk down, gave it an owner and a rollback, and shipped. The alternative — carrying the whole table forever because no one would accept any risk — was the bigger risk, just invisible on paper.
The migration finished three weeks later. The table nobody owned no longer exists, and nothing that matters noticed.
The lesson: a stalled project is rarely a technical problem. It’s a decision nobody feels allowed to make. That’s the work — making the call, owning the risk, writing it down.