polycratia

Most of the time "works on my machine" is a statement about the age of your data, not about your dependencies.

Your local database was built recently, by the current migrations. Every row in it was written by the code you are running right now, so every row has exactly the shape that code expects.

Production holds rows written by versions of the system that are gone.

A column added as nullable three deploys ago and backfilled "later". A status field that picked up a new state after half the records were already written. A ledger entry from before a reference field became mandatory. Current code reads those rows and branches into a path no fixture ever reaches.

Usually nothing crashes. It just quietly takes the wrong branch, and in payments that surfaces much later as an amount nobody can attribute to an obligation, or a reconciliation run where the unmatched bucket grows for reasons the code cannot explain.

So schema history I treat as part of the contract, not as cleanup.

Backfill in the same migration that adds the column, or make the empty value a real named state with explicit handling. Test against a restored, anonymized snapshot instead of hand-built fixtures. In legacy modernization (Python 2 to 3, monolith to services) I assume the oldest rows define the actual contract, not the model definition.

Fixtures encode what the code expects. Production encodes what the code used to do.

I write more about this kind of production reality on my blog: https://polycratia.com/c/c186dc66

The last time old data burned you it was probably a missing backfill, or a state that arrived after the fact...

react

$ new-project --brief

or email hey@polycratia.com