fix: federation DM identity corruption — sync federatedId, guard backfill, remove bad merge criterion

Three bugs that combined to corrupt DM identities during initial sync:

1. Sync endpoint omitted federatedId for group DMs, causing the receiver
   to treat them as 1-on-1 DMs and compute wrong pair hashes — creating
   phantom channels that collide with real ones.

2. backfillHomeUserId unconditionally overwrote existing homeUserIds,
   so a single wrong match would permanently corrupt a user's identity
   and cascade to all subsequent lookups.

3. Migration duplicate-stub Criterion 1 ("shared 1-on-1 DM membership")
   incorrectly merged different users from the same domain who were
   simply having a conversation, destroying one user's identity.
This commit is contained in:
Jannis Braun
2026-04-08 00:49:14 +02:00
parent 2d32d9ae41
commit a496dc01bd
2 changed files with 19 additions and 13 deletions
+3 -13
View File
@@ -789,19 +789,9 @@ export function runMigrations(db: Database.Database): void {
let reason: string | null = null;
// Criterion 1: shared 1-on-1 DM membership
if (!reason) {
const shared = db.prepare(`
SELECT m1.dm_channel_id
FROM dm_members m1
JOIN dm_members m2 ON m1.dm_channel_id = m2.dm_channel_id
JOIN dm_channels c ON c.id = m1.dm_channel_id
WHERE m1.user_id = ? AND m2.user_id = ?
AND c.owner_id IS NULL
LIMIT 1
`).get(a.id, b.id) as { dm_channel_id: string } | undefined;
if (shared) reason = `shared 1-on-1 DM channel ${shared.dm_channel_id}`;
}
// Criterion 1 removed: "shared 1-on-1 DM membership" was wrong —
// two users from the same domain sharing a DM channel doesn't mean
// they're duplicates, it means they're having a conversation.
// Criterion 2: username cross-reference
if (!reason) {