--- name: feedback-migration-renumbering description: "Never renumber an existing migration file to resolve a merge collision — append/take the next free number instead, even if that leaves duplicate-looking prefixes" metadata: node_type: memory type: feedback originSessionId: f8b83784-e0ed-462c-8310-7de6aadc9650 --- When two branches both add a migration with the same numeric prefix (e.g. two different `022_*.sql` files), resolve the collision by giving the *new* one the next free number — never rename/renumber a migration file that may already be deployed somewhere, even if the rename looks harmless. **Why:** In [[project-doot-widget-build|doot]], merge commit `44abf42` renamed `022_calendar_events_recurring_id.sql` → `023_calendar_events_recurring_id.sql` to resolve exactly this kind of collision. But production had already run it under the old name three days earlier. Migrations in this codebase (`internal/store/sqlite.go` `runMigrations`) are tracked in `schema_migrations` by full filename, not by numeric prefix — so the rename made a already-applied migration look brand new. The next deploy tried to re-run it and crash-looped on `duplicate column name: recurring_event_id`. Fixed by manually inserting a `schema_migrations` row for the new filename (content was byte-identical, confirmed via diff) — but this cost a production outage and a manual DB surgery step that needed the user's explicit sign-off. **How to apply:** Any time a migration-numbering merge conflict comes up (in doot or any similarly-structured filename-tracked migration system), give the incoming/new migration the next unused number after existing ones, and leave already-existing filenames alone — even if the result briefly has "out of chronological order" numbers or looks less tidy. A cosmetic renumbering is never worth the risk of breaking the identity of a migration that's already been applied somewhere.