fix(migration): revert V29 to its released checksum, move SEP-31 owner backfill to V31 - #1979
Merged
Merged
Conversation
…r backfill to V31
V29__sep31_customer_id_owner.sql was edited in place after ANCHOR-1248 to add
a backfill INSERT, on the assumption it had never shipped in a tagged release.
That assumption didn't hold everywhere: at least one already-deployed
environment had the original, bare V29 (table creation only) applied before
4.6.0 shipped, so its recorded checksum no longer matched the file, and Flyway
correctly refused to start ("Migration checksum mismatch for migration
version 29").
V29 is reverted to its original, already-released form. The backfill INSERT
(from ANCHOR-1248) and the muxed-account decode repair (V30) both now run
from a new migration, V31, which delegates to V30's existing logic instead of
duplicating it. Since V31 has never been recorded anywhere, Flyway applies it
cleanly regardless of which V29 checksum a given environment already has.
Verified against a live Postgres instance both ways: a fresh install running
the full V1-V31 chain, and a simulated already-broken environment (bare V29
pre-applied, V30/V31 never run) — both converge on the same fully backfilled,
correctly muxed-decoded result. Re-running V31 is a no-op (confirmed), since
the backfill INSERT is `ON CONFLICT (customer_id) DO NOTHING` and the muxed
repair only touches rows where `creator_memo IS NULL`.
Contributor
There was a problem hiding this comment.
Pull request overview
Restores V29’s original checksum and relocates SEP-31 owner backfilling to V31.
Changes:
- Reverts V29 to table creation only.
- Adds V31 to backfill owners and reuse V30’s muxed-account repair.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
V29__sep31_customer_id_owner.sql |
Restores the original migration content. |
V31__backfill_sep31_customer_id_owner.java |
Performs owner backfill and muxed-account repair. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
JiahuiWho
approved these changes
Jul 17, 2026
…at already booted 4.6.0 Reverting V29 to its original form only fixes databases that still hold the original checksum. A database that already booted 4.6.0 successfully recorded the with-backfill checksum instead, and would now fail validation in the opposite direction. Add a Flyway BEFORE_VALIDATE callback that normalizes that one known checksum back to the original before Flyway validates, so both histories are accepted with no manual DB access needed.
…d, scope table check to current schema The callback was a plain @component under platform.configurator, a package none of the four servers' @componentscan lists include - Spring Boot's FlywayAutoConfiguration never saw it, so the checksum mismatch this PR targets would still crash startup. Register it as a @bean in DataBeans (component.share), which every Flyway-enabled server scans. The table-existence check also used a null schema pattern, which matches across every schema in the database. Since data.schema is configurable, that let an already-initialized sibling schema mask a genuinely fresh target schema, passing the check while the subsequent unqualified UPDATE (scoped to the connection's actual current schema) had nothing to update against and would throw. Scope the metadata lookup to connection.getSchema() so the check and the update look at the same table.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
V29__sep31_customer_id_owner.sqlwas edited in place after ANCHOR-1248 to add a backfillINSERT, on the assumption it had never shipped in a tagged release. That held against the 4.5.0 tag, but not against every deployed environment: at least one already had the original, bare V29 (table creation only) applied before 4.6.0 shipped, so its recorded Flyway checksum no longer matched the file, and the app correctly refused to start.This reverts V29 to its original, already-released form (bare
CREATE TABLE), and moves the backfillINSERT(ANCHOR-1248) plus the muxed-account decode repair (V30) into a new migration, V31. V31 delegates to V30's existing decode logic instead of duplicating it.Reverting V29 only fixes environments that still have the original (pre-4.6.0) checksum recorded. Any environment that already booted 4.6.0 successfully recorded the with-backfill checksum for V29, and would now fail validation in the opposite direction once V29 is reverted. Since neither history can be edited by hand (no DB access), this PR also adds
FlywayChecksumCompatibilityCallback, a FlywayBEFORE_VALIDATEcallback that normalizes the with-backfill checksum back to the original one, in-app, before Flyway validates. It's a no-op for every other case (fresh install, or a database that already has the original checksum), so it's safe to leave in place regardless of which of the two known histories a given environment has.The callback is registered as a
@BeaninDataBeans(component.share), since that's the one config package every Flyway-enabled server (platform,sep,observer,event-processor) actually component-scans - each server's@ComponentScanis otherwise scoped to its own controller/component packages and excludesplatform.configurator, so a plain@Componentthere would never reach Spring Boot'sFlywayAutoConfiguration.The table-existence check that guards the normalization scopes its metadata lookup to
connection.getSchema()rather than searching every schema.data.schemais configurable, and an unqualified lookup would treat a fresh target schema as already-initialized if any other schema in the same database happened to have aflyway_schema_historytable - the check would pass, but the subsequent unqualifiedUPDATE(which resolves against the connection's actual current schema) would then fail because that schema's table doesn't exist.Changes
V29__sep31_customer_id_owner.sql: reverted to its original content (byte-identical to the pre-ANCHOR-1248 commit).V31__backfill_sep31_customer_id_owner.java(new): runs the same backfillINSERTthat used to live in V29, then delegates toV30__backfill_muxed_sep31_customer_id_owner's existingmigrate()for the muxed-account repair.FlywayChecksumCompatibilityCallback.java(new): Flyway callback that rewrites V29's recorded checksum from the 4.6.0 with-backfill value back to the original value, only when the with-backfill value is actually present in the connection's current schema.DataBeans.java: registers the callback as a@Beanso every Flyway-enabled server picks it up.Context
Production incident: the
event-processorservice failed to start after the 4.6.0 release withFlywayValidateException: Migration checksum mismatch for migration version 29-Applied to database: 1190516276(the bare, pre-backfill V29) vs.Resolved locally: 1803170936(the with-backfill V29 shipped in 4.6.0).Testing
./gradlew :core:test :platform:test- BUILD SUCCESSFUL.sep31_transactionhistory (plain and muxed callers) - applies cleanly in order,sep31_customer_id_ownerends up fully and correctly backfilled. The new callback is a verified no-op here (flyway_schema_historydoesn't exist yet atBEFORE_VALIDATEtime; the callback detects that and returns early instead of erroring).flyway_schema_historywith that exact checksum (1803170936) via a real migrate run against the old with-backfill V29 file, then ran Flyway again against the reverted V29 with the callback registered - validation succeeds and the recorded checksum is rewritten to 1190516276. Confirmed as a negative control that the same scenario without the callback throws the checksum mismatch (in the reverse direction from the original incident, as expected).publicalready holding an initializedflyway_schema_history, pointed a fresh, never-migratedfresh_targetschema (viacurrentSchema=fresh_target) at the same database and confirmed it migrates cleanly - i.e.publichaving history doesn't fool the check into skipping/misinterpretingfresh_target's own state.Documentation
N/A
Known limitations
This normalizes exactly the two checksums known from this incident (the original V29 and the 4.6.0 with-backfill V29). It does not attempt to handle a third, unknown checksum for V29 - that would still fail validation and require a manual
flyway repair. Any environment currently crash-looping on this checksum mismatch, in either direction, can redeploy directly once this ships - no manual DB access needed.