---
title: "A 418-line tool now reads our recovery file as plain text"
canonical: https://dxdev.com/everyday-ai/list-i-could-not-trust/
datePublished: 2026-01-28
---
A [1,477-line recovery file](/blog/copy-first-remap-ids-second-site-recovery-engine/) puts a customer's site back together from handwritten lists, one comma-separated list of columns (the named fields in a database table) for every table. Nothing checks those lists against the 14,536 columns the database actually stores. If someone adds a column and forgets to add it to the matching list, recovery still runs, still reports success, and still rebuilds the site, minus that one column. No error appears and no log says anything was left behind. The only way anyone would find out is a customer noticing that a feature's data is missing.

## A fresh export and an uncomfortable question

We pulled a fresh export of everything the database stores, to compare against those lists. It came back with one row per column, spread across hundreds of tables. We looked at that next to the hand-typed column names and had to ask a question we did not like: how would we ever know if the two had drifted apart?

Nothing would tell us. That was the part that worried us. The recovery file did not fail loudly when a list fell behind. Say we added a new column to a table during ordinary feature work and forgot to add it to the matching recovery list two files away. Recovery would still run and still report success. It would still put a site back together for a customer. It just would not carry that one column. Recovery would not break. It would look fine while being wrong.

For a long stretch, our answer to that risk was to remember. Every time we added a column, we were supposed to also update the recovery list. That is a hope rather than a system, and we had been running on it without ever proving the lists were still accurate. We could not point to a day the drift actually happened. We also could not point to a day we had checked closely enough to know it hadn't.

## Building the check

So we stopped trying to remember and built something to check instead. It is a 418-line tool that reads the recovery file as plain text, pulls out every column list it declares, and compares each one against that table's real columns from the fresh export. It reports two things: columns the database has that the recovery code does not copy, and columns the recovery code still names that no longer exist. The report is organized into four sections: generic tables, the customer records, the scores tables, and the stat tables. The state you want is all four with nothing under them.

## Deciding which side to trust

Getting the comparison right meant deciding which side to believe. Our first instinct was that the database's current shape should be the source of truth, since that is what the data looks like today. That instinct was wrong. Some columns are calculated fields. Some are identity numbers the database assigns itself. Some are timestamps that should be set fresh on arrival rather than copied. If the database were the final word, every one of those would show up as a false problem, and we would spend our time maintaining a second list just to explain away the first.

The recovery list had to be treated as the actual promise, the statement of exactly what recovery is responsible for carrying. The fresh export became the thing checked against that promise. The only question worth asking was whether the database had grown columns the promise did not know about yet.

## A fragile tool, on purpose

The tool is not fancy. The recovery file is written in an old scripting language with no real parser available to us, so the tool counts opening and closing curly braces to find the right chunk of code. A few plain rules of thumb keep it from flagging identity columns as missing. That is a fragile way to read a program, and we would never trust it against a file that changed often or was edited by more than one person. It is the right tool here because this file barely changes, and a small fragile check that actually runs beats a perfect one that only exists as an instruction to remember.

## What the silence means now

The 418 lines of the tool changed what an empty report says. A recovery report with four empty sections is now a claim that every list still matches the database, checked that day. Before, it was only a hope that we had remembered to update the lists. If your own recovery process restores from hand-maintained lists, find out whether anything compares those lists to the columns the database really holds. Without that comparison, recovery can report success while leaving data behind, and no one learns of it until a customer notices.
