feat(platform): Phase 673 member heal, presence dedupe, and audit spans

Extend partition heal with member list and voice occupancy recovery,
presence gossip dedupe via _gossipPresenceIfNew, kick span metadata, and
member.role.add/remove audit on custom role assignment.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-02 22:05:03 -04:00
co-authored by Cursor
parent 6fcabcae33
commit ce0001c8c3
+85 -3
View File
@@ -606,6 +606,8 @@ class PearcordPlatform extends EventEmitter {
this._threadCreateRateByUser = new Map()
/** Dedupe thread metadata gossip ingest (Phase 672). */
this._threadMetaGossipKeys = new Set()
/** Dedupe presence gossip fanout (Phase 673). */
this._presenceGossipKeys = new Set()
/** Multi-select forum tag filters (Phase 672). */
this._forumTagFilters = []
}
@@ -1550,7 +1552,9 @@ class PearcordPlatform extends EventEmitter {
const pinHeal = await this._healPinListOnPartition(gid).catch(() => ({ relisted: 0 }))
const searchHeal = await this._healSearchIndexOnPartition(gid).catch(() => ({ relisted: 0 }))
const threadHeal = await this._healThreadMetadataOnPartition(gid).catch(() => ({ relisted: 0 }))
return { voiceApplied, emojiSlots, automodReconciled, voiceNoteHeal, attachmentHeal, embedHeal, reactionHeal, stickerHeal, pinHeal, searchHeal, threadHeal }
const memberHeal = await this._healMemberListOnPartition(gid).catch(() => ({ relisted: 0 }))
const voiceOccHeal = await this._healVoiceOccupancyOnPartition(gid).catch(() => ({ relisted: 0 }))
return { voiceApplied, emojiSlots, automodReconciled, voiceNoteHeal, attachmentHeal, embedHeal, reactionHeal, stickerHeal, pinHeal, searchHeal, threadHeal, memberHeal, voiceOccHeal }
}
async _healReactionListOnPartition (guildId) {
@@ -10980,6 +10984,12 @@ class PearcordPlatform extends EventEmitter {
})
}
_gossipPresenceIfNew (payload) {
if (!payload?.userId || !this.guild) return
if (!this._shouldGossipPresence(payload)) return
this.guild.gossipPresence(payload)
}
_ingestPresenceWithProfile (payload) {
if (!payload?.userId || !this.presence) return
this.presence.ingest(payload)
@@ -13366,6 +13376,59 @@ class PearcordPlatform extends EventEmitter {
return true
}
_shouldGossipPresence (payload) {
if (!payload?.userId) return true
const hash = `${payload.userId}:${payload.status || ''}:${payload.at || 0}:${payload.vectorSeq || 0}`
if (this._presenceGossipKeys.has(hash)) return false
this._presenceGossipKeys.add(hash)
if (this._presenceGossipKeys.size > 8192) {
const first = this._presenceGossipKeys.values().next().value
if (first) this._presenceGossipKeys.delete(first)
}
return true
}
async _healMemberListOnPartition (guildId) {
const gid = guildId || this.guild?.guild?.id
if (!gid || !this.guild?.listMembers) return { relisted: 0, skipped: true }
const span = this.log.time('member.heal', { spanKind: 'member.heal', guildId: gid })
try {
const members = await this.guild.listMembers().catch(() => [])
let relisted = 0
for (const mem of members.slice(0, 128)) {
if (this.guild?.gossipMemberPage && mem?.userId) {
this.guild.gossipMemberPage({ guildId: gid, userId: mem.userId, at: Date.now() })
relisted++
}
}
span.end({ relisted, rowCount: members.length })
return { relisted, rowCount: members.length }
} catch (err) {
this.log.error('member.heal error', { guildId: gid, error: err?.message || String(err) })
span.fail(err)
return { relisted: 0, error: err?.message || String(err) }
}
}
async _healVoiceOccupancyOnPartition (guildId) {
const gid = guildId || this.guild?.guild?.id
if (!gid) return { relisted: 0, skipped: true }
const span = this.log.time('voice.heal', { spanKind: 'voice.heal', guildId: gid })
try {
const rows = this._exportVoiceOccupancyForSync(await this.guild?.listChannels?.().catch(() => []) || [])
let relisted = 0
if (rows?.length) {
relisted = await this._ingestVoiceOccupancyBundle(gid, rows)
}
span.end({ relisted, rowCount: rows?.length || 0 })
return { relisted, rowCount: rows?.length || 0 }
} catch (err) {
this.log.error('voice.heal error', { guildId: gid, error: err?.message || String(err) })
span.fail(err)
return { relisted: 0, error: err?.message || String(err) }
}
}
async _healThreadMetadataOnPartition (guildId) {
const gid = guildId || this.guild?.guild?.id
if (!gid || !this.guild?.listChannels) return { relisted: 0, skipped: true }
@@ -14141,11 +14204,24 @@ class PearcordPlatform extends EventEmitter {
throw new Error('cannot change owner role assignments')
}
await this._initGuildRoles(this.guild.guild.id)
const prevLink = await this.guildRoles.getMemberRoleIds(this.guild.guild.id, userId).catch(() => null)
const prevIds = new Set((prevLink?.roleIds || []).map(String))
const link = await this.guildRoles.setMemberRoleIds(
this.guild.guild.id,
userId,
roleIds
)
const nextIds = new Set((roleIds || []).map(String))
for (const rid of nextIds) {
if (!prevIds.has(rid)) {
await this._audit('member.role.add', { guildId: this.guild.guild.id, targetId: userId, roleId: rid })
}
}
for (const rid of prevIds) {
if (!nextIds.has(rid)) {
await this._audit('member.role.remove', { guildId: this.guild.guild.id, targetId: userId, roleId: rid })
}
}
this.guild.gossipMemberCustomRoles(link)
this.emit('guild-member-roles', link)
await this._fanoutAppEvent(APP_EVENTS.MEMBER_ROLE_UPDATE, { memberRoles: link })
@@ -23478,13 +23554,19 @@ class PearcordPlatform extends EventEmitter {
this.guild.gossipKick(payload)
this.emit('kick', payload)
const memberCount = (await this.guild.listMembers()).length
const targetMem = await this.db.get(COLLECTIONS.MEMBERS, {
guildId: payload.guildId,
userId
}).catch(() => null)
span.end({
userId,
guildId,
targetName: targetMem?.nickname || targetMem?.displayName || null,
hasReason: !!reason,
reasonLen: String(reason || '').trim().length,
removedMember: true,
spanKind: 'kick.member',
parentId: this.activeChannelId || null,
activeChannelId: this.activeChannelId,
memberCount,
guildCount: (this.guilds || []).length
@@ -25515,7 +25597,7 @@ class PearcordPlatform extends EventEmitter {
payload.vectorSeq = vec?.seq
}
this.emit('presence', payload)
if (this.guild) this.guild.gossipPresence(payload)
if (this.guild) this._gossipPresenceIfNew(payload)
if (this.contacts) {
this.contacts.broadcastPresence({
userId: payload.userId,
@@ -25538,7 +25620,7 @@ class PearcordPlatform extends EventEmitter {
})
payload.vectorSeq = vec?.seq
}
if (this.guild) this.guild.gossipPresence(payload)
if (this.guild) this._gossipPresenceIfNew(payload)
if (this.contacts) {
this.contacts.broadcastPresence({
userId: base.userId,