Every large migration eventually reduces to one question: how do you prove that the new system holds the same truth as the old one? Cutover weekends answer it with a freeze — stop the world, copy the data, compare totals, resume. That works until the business cannot stop, at which point the freeze is not available and the interesting engineering starts.
The pattern we keep returning to is dual-write behind a router, with reconciliation running continuously rather than as a final gate. Writes go to both systems; a job asserts equality at the smallest meaningful unit — usually the account, not the aggregate — and traffic moves in cohorts small enough that any single cohort can be reversed inside a minute.
The reconciliation harness is not scaffolding for the migration. It is the control you keep afterwards.
The subtlety is in what you reconcile. Comparing daily totals feels efficient and hides exactly the errors you care about, because offsetting mistakes net to zero. Per-entity comparison is more expensive and it is the only version that produces an artefact a regulator will accept.
What surprises most teams is what happens after the migration completes. The reconciliation job, built as temporary scaffolding, turns out to be a permanent control — a continuous assertion that two systems still agree. We now scope it as a deliverable in its own right rather than as migration overhead.