feat(federation): startup sweep reconciles drifted 1-on-1 DM federatedIds — heals pre-fix re-attaches (reattach-dm-reconcile spec §3.3)

This commit is contained in:
Jannis Braun
2026-07-03 12:36:17 +02:00
parent 0bb4ef8cad
commit 011a9be92a
3 changed files with 155 additions and 1 deletions
+33
View File
@@ -7099,6 +7099,39 @@ export function reconcileDmChannelFederatedId(
return { action: 'merged', channelId, targetChannelId: targetId, affectedUserIds: affected };
}
/**
* Startup sweep: reconcile any 1-on-1 DM channel whose stored federatedId has
* drifted from its members' current home identities (reattach-dm-reconcile
* spec §3.3). Heals accounts re-attached before inline reconciliation shipped
* (e.g. the live split-conversation duplicate). Idempotent; a noop on a clean DB.
*/
export function reconcileDriftedDmFederatedIds(): void {
const rawDb = getRawDb();
const candidates = rawDb.prepare(`
SELECT c.id FROM dm_channels c
WHERE c.deleted_at IS NULL
AND c.federated_id IS NOT NULL
AND (SELECT count(*) FROM dm_members m WHERE m.dm_channel_id = c.id) = 2
`).all() as Array<{ id: string }>;
if (candidates.length === 0) return;
let rekeyed = 0;
let merged = 0;
rawDb.transaction(() => {
for (const c of candidates) {
// A prior merge in this loop may have deleted this id — reconcile returns
// noop for a missing/mutated channel, so this is safe.
const r = reconcileDmChannelFederatedId(rawDb, c.id);
if (r.action === 'rekeyed') rekeyed++;
else if (r.action === 'merged') merged++;
}
})();
if (rekeyed > 0 || merged > 0) {
console.log(`[federation] DM federatedId reconciliation: rekeyed ${rekeyed}, merged ${merged}`);
}
}
/**
* Remove dead-incarnation artifacts produced by pre-fix initial syncs
* (dead-incarnation spec §3.4): DM channels with no native member, and