fix: batch merge notifications and add storage failure warning

Fixes Copilot audit issues #2 and #4 (code we added):

Issue #2 - Multiple Event Emissions (MEDIUM severity):
- Changed: Collect all merge notifications in array
- Emit: Single batched event instead of multiple separate events
- Impact: Better performance, fewer DB transactions, no UI flickering

Issue #4 - Storage Validation (MEDIUM severity):
- Added: Warning log when LID-PN mappings fail to store
- Tracks: errors count vs notifications sent for debugging
- Improves: Observability of partial storage failures

Technical changes:
- Declared mergeNotifications array before loop
- Compute mergedAt timestamp once (not per iteration)
- Push notifications to array instead of emitting in loop
- Emit single chats.update with all notifications
- Log warning with detailed counts if result.errors > 0

Benefits:
 100x fewer events for 100 mappings (1 vs 100)
 Better consumer performance (ZPRO)
 Improved observability of storage failures
 Zero breaking changes (backward compatible)

Note: Did NOT fix Issue #3 (Prototype Pollution) as it's in
pre-existing code (event-buffer.ts), not code we added.

https://claude.ai/code/session_01SoNUGBEWbJwWWws3F2fuzh
This commit is contained in:
Claude
2026-02-09 21:39:38 +00:00
parent a039291407
commit 1a3c405345
+28 -10
View File
@@ -1309,6 +1309,10 @@ export const makeChatsSocket = (config: SocketConfig) => {
// Automatic chat merge: notify consumers about LID→PN mapping
// This allows ZPRO and other consumers to merge/rename chats accordingly
// Collect all merge notifications to emit in a single batch
const mergeNotifications: ChatUpdate[] = []
const mergedAt = Date.now()
for (const mapping of mappings) {
const lidUser = jidNormalizedUser(mapping.lid)
const pnUser = jidNormalizedUser(mapping.pn)
@@ -1316,20 +1320,34 @@ export const makeChatsSocket = (config: SocketConfig) => {
if (lidUser && pnUser && lidUser !== pnUser) {
logger.debug(
{ lid: lidUser, pn: pnUser },
'emitting chat update for LID→PN merge notification'
'collected chat update for LID→PN merge notification'
)
// Emit chat update indicating this chat should be merged/renamed from LID to PN
ev.emit('chats.update', [
{
id: pnUser,
merged: true,
previousId: lidUser,
mergedAt: Date.now()
}
])
mergeNotifications.push({
id: pnUser,
merged: true,
previousId: lidUser,
mergedAt
})
}
}
// Emit single batch of merge notifications for better performance
if (mergeNotifications.length > 0) {
logger.debug(
{ count: mergeNotifications.length },
'emitting batch of chat merge notifications'
)
ev.emit('chats.update', mergeNotifications)
}
// Log warning if some mappings failed to store
if (result.errors > 0) {
logger.warn(
{ errors: result.errors, total: mappings.length, notified: mergeNotifications.length },
'some LID-PN mappings failed to store, but merge notifications were sent'
)
}
} catch (error) {
logger.warn({ count: mappings.length, error }, 'Failed to store LID-PN mappings')
}