Changes IMAP email ID format from accountId:uid to accountId:mailboxPath:uid in _refreshFlagsImap and _fetchAndUpsertImap
Adds schema migration v41 that re-derives IDs for existing IMAP rows, updates email_bodies.email_id FK, patches thread_id fields that pointed at the old email ID, and rebuilds threads for IMAP accounts
Bumps dbSchemaVersion from 40 to 41
Root cause
IMAP UIDs are mailbox-scoped: UID 50 in INBOX and UID 50 in Archive are different emails. The old composite key accountId:uid caused insertOnConflictUpdate to silently overwrite whichever arrived first, corrupting the local DB in ways a force-full-sync could not fix.
Migration safety
The migration uses PRAGMA defer_foreign_keys = ON so both email_bodies.email_id and emails.id can be updated sequentially within the same migration transaction without a transient FK violation. Threads are deleted and rebuilt from the corrected email rows.
Test plan
New v40→v41 migration test verifies IDs, email_bodies, thread_ids, and threads are updated correctly
New unit test verifies same-UID emails in different mailboxes get independent IDs and are both retrievable
## Summary
- Changes IMAP email ID format from `accountId:uid` to `accountId:mailboxPath:uid` in `_refreshFlagsImap` and `_fetchAndUpsertImap`
- Adds schema migration v41 that re-derives IDs for existing IMAP rows, updates `email_bodies.email_id` FK, patches `thread_id` fields that pointed at the old email ID, and rebuilds threads for IMAP accounts
- Bumps `dbSchemaVersion` from 40 to 41
## Root cause
IMAP UIDs are mailbox-scoped: UID 50 in INBOX and UID 50 in Archive are different emails. The old composite key `accountId:uid` caused `insertOnConflictUpdate` to silently overwrite whichever arrived first, corrupting the local DB in ways a force-full-sync could not fix.
## Migration safety
The migration uses `PRAGMA defer_foreign_keys = ON` so both `email_bodies.email_id` and `emails.id` can be updated sequentially within the same migration transaction without a transient FK violation. Threads are deleted and rebuilt from the corrected email rows.
## Test plan
- New `v40→v41` migration test verifies IDs, email_bodies, thread_ids, and threads are updated correctly
- New unit test verifies same-UID emails in different mailboxes get independent IDs and are both retrievable
- Full unit suite: all 338 tests pass
Closes #502
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
accountId:uidtoaccountId:mailboxPath:uidin_refreshFlagsImapand_fetchAndUpsertImapemail_bodies.email_idFK, patchesthread_idfields that pointed at the old email ID, and rebuilds threads for IMAP accountsdbSchemaVersionfrom 40 to 41Root cause
IMAP UIDs are mailbox-scoped: UID 50 in INBOX and UID 50 in Archive are different emails. The old composite key
accountId:uidcausedinsertOnConflictUpdateto silently overwrite whichever arrived first, corrupting the local DB in ways a force-full-sync could not fix.Migration safety
The migration uses
PRAGMA defer_foreign_keys = ONso bothemail_bodies.email_idandemails.idcan be updated sequentially within the same migration transaction without a transient FK violation. Threads are deleted and rebuilt from the corrected email rows.Test plan
v40→v41migration test verifies IDs, email_bodies, thread_ids, and threads are updated correctlyCloses #502