Phase 745: extract sync health patch, gossip view, push schedule mixins

Non-breaking refactor: move _patchGuildSyncHealth and health count refresh,
gossip lane alert thresholds, sparse ack view rows, compact health slice,
discovery listing expiry view, and guild sync push/request burst schedulers
out of platform-pearcord-platform-class.js. Manifest rows 76→79; runtime
registry 16→19. Sync health and mesh scheduling behavior unchanged.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-03 11:23:08 -04:00
co-authored by Cursor
parent 88a1624a2c
commit c05223413c
7 changed files with 233 additions and 186 deletions
+2
View File
@@ -54,6 +54,8 @@ Application facade: one `PearcordPlatform` class that wires identity, database,
**Phase 723 (v0.8.699):** Dedicated slash registry & invoke audit export JSON — `slash-registry-json-mixin.js`, `slash-invoke-audit-json-mixin.js`, spans `slash-registry.json` / `slash-invoke-audit.json`, `getSlashInvokeAuditExportJsonExport`, `clearSlashInvokeAuditExportJsonExports`, deep links `openSlashRegistryJson` / `openSlashInvokeAuditJson`. Bundle: `npm run test:ci-phase723`.
**Phase 745 (v0.8.721):** `platform-guild-sync-health-patch-mixin.js`, `platform-guild-sync-gossip-view-mixin.js`, `platform-guild-sync-push-schedule-mixin.js` (79 mixin rows, 19 runtime mixins); sync health patch, gossip lane alerts, sparse ack view, push/request burst scheduling. Bundle: `npm run test:ci-phase745`.
**Phase 744 (v0.8.720):** `platform-guild-sync-watermark-mixin.js`, `platform-guild-gossip-outbox-mixin.js`, `platform-guild-sync-bandwidth-mixin.js` (76 mixin rows, 16 runtime mixins); sync watermarks/acks, gossip outbox queue/flush, bandwidth caps and member roster paging. Bundle: `npm run test:ci-phase744`.
**Phase 743 (v0.8.719):** `platform-mesh-view-mixin.js`, `platform-mesh-logging-mixin.js`, `platform-member-page-burst-mixin.js` (73 mixin rows, 13 runtime mixins); sync fanout watermarks, mesh status summary, mesh span logging, topic pool peer tracking, member page burst limits. Bundle: `npm run test:ci-phase743`.
+88
View File
@@ -0,0 +1,88 @@
'use strict'
const { getListingTtlMs } = require('pearcord-discovery')
const platformGuildSyncGossipViewMixin = {
_gossipLaneAlertThresholds () {
return {
message: Math.max(
8,
Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_MESSAGE) || 48
),
presence: Math.max(
8,
Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_PRESENCE) || 32
),
audit: Math.max(8, Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_AUDIT) || 24),
default: Math.max(8, Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_DEFAULT) || 16)
}
},
_gossipLaneAlertsFromCounts (laneCounts = {}) {
const thresholds = this._gossipLaneAlertThresholds()
const alerts = []
for (const lane of ['message', 'presence', 'audit', 'default']) {
const count = Number(laneCounts[lane]) || 0
const threshold = thresholds[lane] || 16
if (count < threshold) continue
alerts.push({
lane,
count,
threshold,
severity: count >= threshold * 2 ? 'high' : 'warn'
})
}
return alerts
},
_sparseAckSyncRowsForView (guildId) {
const id = guildId || this.guild?.guild?.id
if (!id) return []
const cursors = this._sparseAckCursorByGuild.get(id) || {}
return Object.entries(cursors).map(([channelId, offset]) => ({
channelId,
offset: Number(offset) || 0
}))
},
_compactGuildSyncHealthSlice (guildId) {
const row = this.getGuildSyncHealth(guildId)
if (!row) return null
return {
guildId,
pending: !!row.pending,
syncProgressPct: Number(row.syncProgressPct) || 0,
peers: Number(row.peers) || 0,
messageCount: Number(row.messageCount) || 0,
memberCount: Number(row.memberCount) || 0,
syncMode: row.syncMode || 'gossip',
syncWatermark: row.syncWatermark || null,
lastIngestAt: Number(row.lastIngestAt) || 0,
hostWired: !!row.hostWired,
presenceVectorSize: Number(row.presenceVectorSize) || 0
}
},
_discoveryListingExpiryForView () {
const gid = this.guild?.guild?.id
if (!gid) return null
const listing =
(this._cachedPublicListings || []).find((r) => r.id === gid) || null
const lastAt =
listing?.lastAnnouncedAt ||
this._discoveryListingRefreshByGuild.get(gid) ||
null
if (!lastAt) return null
const ttlMs = getListingTtlMs()
const expiresAt = lastAt + ttlMs
return {
guildId: gid,
lastAnnouncedAt: lastAt,
expiresAt,
ttlMs,
remainingMs: Math.max(0, expiresAt - Date.now())
}
}
}
module.exports = { platformGuildSyncGossipViewMixin }
+76
View File
@@ -0,0 +1,76 @@
'use strict'
const sharedScope = require('pearcord-shared')
const platformGuildSyncHealthPatchMixin = {
_patchGuildSyncHealth (patch = {}) {
const guildId = patch.guildId || this.guild?.guild?.id
if (!guildId) return null
const prev = this._guildSyncHealthByGuild.get(guildId) || {
guildId,
peers: 0,
hostWired: false,
messageCount: 0,
memberCount: 0,
pending: true,
reason: null,
lastIngestAt: 0,
hostPublicKey: null,
syncWatermark: { sinceTimestamp: 0, sinceMessageId: null },
syncProgressPct: 0,
pendingGossipCount: 0,
lastBundleBytes: 0,
estimatedBytesTotal: 0,
syncFailed: false,
syncMode: 'gossip'
}
const row = {
...prev,
...patch,
guildId,
updatedAt: Date.now()
}
if (row.syncWatermark && row.messageCount > 0) {
const pct = this._computeGuildSyncProgressPct(row.guildId, row)
if (pct != null) row.syncProgressPct = pct
}
this._guildSyncHealthByGuild.set(guildId, row)
if (this.guild?.guild?.id === guildId) this.emit('guild-sync-health', row)
this._scheduleBroadcastGuildSyncHealthToSettingsMesh(guildId)
return row
},
async _refreshGuildSyncHealthCounts (guildId) {
const gid = guildId || this.guild?.guild?.id
if (!gid) return null
const channelId = this.activeChannelId
let messageCount = 0
if (channelId) {
const rows = await this.db.find(sharedScope.COLLECTIONS.MESSAGES, { channelId })
messageCount = rows.length
}
let memberCount = 0
if (this.guild?.guild?.id === gid) {
memberCount = (await this.guild.listMembers()).length
} else {
memberCount = (await this.db.find(sharedScope.COLLECTIONS.MEMBERS, { guildId: gid })).length
}
const prev = this._guildSyncHealthByGuild.get(gid)
const hostPk = await this._lookupGuildHostPublicKey(
(await this.db.get(sharedScope.COLLECTIONS.GUILDS, { id: gid })) || { id: gid }
)
return this._patchGuildSyncHealth({
guildId: gid,
peers:
this.guild?.guild?.id === gid
? this.guild.peers?.size ?? 0
: prev?.peers ?? 0,
messageCount,
memberCount,
hostPublicKey: hostPk,
pending: messageCount === 0 && memberCount <= 1
})
}
}
module.exports = { platformGuildSyncHealthPatchMixin }
@@ -0,0 +1,48 @@
'use strict'
const platformGuildSyncPushScheduleMixin = {
_scheduleGuildSyncPushCoalesced (opts = {}, windowMs = 2000) {
const guildId = this.guild?.guild?.id
if (!guildId) return
if (this._guildSyncPushCoalesceTimer) {
clearTimeout(this._guildSyncPushCoalesceTimer)
}
this._guildSyncPushCoalesceTimer = setTimeout(() => {
this._guildSyncPushCoalesceTimer = null
if (this.guild?.guild?.id !== guildId) return
if (this._isGuildSyncPushHalted(guildId)) return
void this._pushGuildSyncToMesh(opts).catch(() => {})
}, Math.max(500, Number(windowMs) || 2000))
},
_scheduleGuildSyncPushBurst (delays = null, opts = {}) {
const guildId = this.guild?.guild?.id
if (!guildId || this._isGuildSyncPushHalted(guildId)) return
const burst = delays || this._guildSyncBurstDelaysFromRtt()
for (const ms of burst) {
setTimeout(() => {
if (this.guild?.guild?.id !== guildId) return
if (this._isGuildSyncPushHalted(guildId)) return
this._pushGuildSyncToMesh(opts).catch(() => {})
}, ms)
}
},
_scheduleGuildSyncRequestBurst (delays = [0, 600, 1800, 4000, 8000]) {
const guildId = this.guild?.guild?.id
if (!guildId) return
this._guildSyncRequestBackoffGen = (this._guildSyncRequestBackoffGen || 0) + 1
const gen = this._guildSyncRequestBackoffGen
for (let i = 0; i < delays.length; i++) {
const base = delays[i]
const ms = base * (i > 0 ? Math.pow(1.5, i - 1) : 1)
setTimeout(() => {
if (gen !== this._guildSyncRequestBackoffGen) return
if (this.guild?.guild?.id !== guildId) return
this._requestGuildSyncFromHost()
}, Math.round(ms))
}
}
}
module.exports = { platformGuildSyncPushScheduleMixin }
+4 -1
View File
@@ -4,7 +4,7 @@
* Ordered PearcordPlatform prototype mixin registration (Phase 730).
* Preserves assign order from index.js / apply-platform-mixins (Phase 727).
*/
const PLATFORM_MIXIN_ASSIGNMENT_COUNT = 76
const PLATFORM_MIXIN_ASSIGNMENT_COUNT = 79
const PLATFORM_MIXIN_ASSIGNMENTS = [
{ module: './polls-scheduling', export: 'pollSchedulingMixin' },
@@ -82,6 +82,9 @@ const PLATFORM_MIXIN_ASSIGNMENTS = [
{ module: './platform-guild-sync-watermark-mixin', export: 'platformGuildSyncWatermarkMixin' },
{ module: './platform-guild-gossip-outbox-mixin', export: 'platformGuildGossipOutboxMixin' },
{ module: './platform-guild-sync-bandwidth-mixin', export: 'platformGuildSyncBandwidthMixin' },
{ module: './platform-guild-sync-health-patch-mixin', export: 'platformGuildSyncHealthPatchMixin' },
{ module: './platform-guild-sync-gossip-view-mixin', export: 'platformGuildSyncGossipViewMixin' },
{ module: './platform-guild-sync-push-schedule-mixin', export: 'platformGuildSyncPushScheduleMixin' },
{ module: './platform-diagnostics-mixin', export: 'platformDiagnosticsMixin' }
]
+10 -183
View File
@@ -1245,42 +1245,7 @@ class PearcordPlatform extends EventEmitter {
return `${guildId || ''}:${key.channelId}:${key.messageId}:${key.emoji}:${key.userId}`
}
_patchGuildSyncHealth (patch = {}) {
const guildId = patch.guildId || this.guild?.guild?.id
if (!guildId) return null
const prev = this._guildSyncHealthByGuild.get(guildId) || {
guildId,
peers: 0,
hostWired: false,
messageCount: 0,
memberCount: 0,
pending: true,
reason: null,
lastIngestAt: 0,
hostPublicKey: null,
syncWatermark: { sinceTimestamp: 0, sinceMessageId: null },
syncProgressPct: 0,
pendingGossipCount: 0,
lastBundleBytes: 0,
estimatedBytesTotal: 0,
syncFailed: false,
syncMode: 'gossip'
}
const row = {
...prev,
...patch,
guildId,
updatedAt: Date.now()
}
if (row.syncWatermark && row.messageCount > 0) {
const pct = this._computeGuildSyncProgressPct(row.guildId, row)
if (pct != null) row.syncProgressPct = pct
}
this._guildSyncHealthByGuild.set(guildId, row)
if (this.guild?.guild?.id === guildId) this.emit('guild-sync-health', row)
this._scheduleBroadcastGuildSyncHealthToSettingsMesh(guildId)
return row
}
getGuildSyncHealth (guildId) {
const id = guildId || this.guild?.guild?.id
@@ -1298,37 +1263,7 @@ class PearcordPlatform extends EventEmitter {
}
}
async _refreshGuildSyncHealthCounts (guildId) {
const gid = guildId || this.guild?.guild?.id
if (!gid) return null
const channelId = this.activeChannelId
let messageCount = 0
if (channelId) {
const rows = await this.db.find(sharedScope.COLLECTIONS.MESSAGES, { channelId })
messageCount = rows.length
}
let memberCount = 0
if (this.guild?.guild?.id === gid) {
memberCount = (await this.guild.listMembers()).length
} else {
memberCount = (await this.db.find(sharedScope.COLLECTIONS.MEMBERS, { guildId: gid })).length
}
const prev = this._guildSyncHealthByGuild.get(gid)
const hostPk = await this._lookupGuildHostPublicKey(
(await this.db.get(sharedScope.COLLECTIONS.GUILDS, { id: gid })) || { id: gid }
)
return this._patchGuildSyncHealth({
guildId: gid,
peers:
this.guild?.guild?.id === gid
? this.guild.peers?.size ?? 0
: prev?.peers ?? 0,
messageCount,
memberCount,
hostPublicKey: hostPk,
pending: messageCount === 0 && memberCount <= 1
})
}
get guildOpenNoViewableChannels () {
return !!this._guildOpenNoViewableChannels
@@ -6350,51 +6285,11 @@ class PearcordPlatform extends EventEmitter {
}
}
_scheduleGuildSyncPushCoalesced (opts = {}, windowMs = 2000) {
const guildId = this.guild?.guild?.id
if (!guildId) return
if (this._guildSyncPushCoalesceTimer) {
clearTimeout(this._guildSyncPushCoalesceTimer)
}
this._guildSyncPushCoalesceTimer = setTimeout(() => {
this._guildSyncPushCoalesceTimer = null
if (this.guild?.guild?.id !== guildId) return
if (this._isGuildSyncPushHalted(guildId)) return
void this._pushGuildSyncToMesh(opts).catch(() => {})
}, Math.max(500, Number(windowMs) || 2000))
}
_gossipLaneAlertThresholds () {
return {
message: Math.max(
8,
Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_MESSAGE) || 48
),
presence: Math.max(
8,
Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_PRESENCE) || 32
),
audit: Math.max(8, Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_AUDIT) || 24),
default: Math.max(8, Number(process.env.PEARCORD_GOSSIP_LANE_ALERT_DEFAULT) || 16)
}
}
_gossipLaneAlertsFromCounts (laneCounts = {}) {
const thresholds = this._gossipLaneAlertThresholds()
const alerts = []
for (const lane of ['message', 'presence', 'audit', 'default']) {
const count = Number(laneCounts[lane]) || 0
const threshold = thresholds[lane] || 16
if (count < threshold) continue
alerts.push({
lane,
count,
threshold,
severity: count >= threshold * 2 ? 'high' : 'warn'
})
}
return alerts
}
getMeshStabilityStats (guildId) {
const id = guildId || this.guild?.guild?.id
@@ -6477,15 +6372,7 @@ class PearcordPlatform extends EventEmitter {
}
}
_sparseAckSyncRowsForView (guildId) {
const id = guildId || this.guild?.guild?.id
if (!id) return []
const cursors = this._sparseAckCursorByGuild.get(id) || {}
return Object.entries(cursors).map(([channelId, offset]) => ({
channelId,
offset: Number(offset) || 0
}))
}
exportGuildSyncDiagnostics (guildId) {
const id = guildId || this.guild?.guild?.id
@@ -6677,26 +6564,7 @@ class PearcordPlatform extends EventEmitter {
return out
}
_discoveryListingExpiryForView () {
const gid = this.guild?.guild?.id
if (!gid) return null
const listing =
(this._cachedPublicListings || []).find((r) => r.id === gid) || null
const lastAt =
listing?.lastAnnouncedAt ||
this._discoveryListingRefreshByGuild.get(gid) ||
null
if (!lastAt) return null
const ttlMs = getListingTtlMs()
const expiresAt = lastAt + ttlMs
return {
guildId: gid,
lastAnnouncedAt: lastAt,
expiresAt,
ttlMs,
remainingMs: Math.max(0, expiresAt - Date.now())
}
}
/** Headless/agentctl: apply bundle roster fields to guild sync health (smokes). */
recordMemberRosterSyncSnapshot (guildId, bundleSlice = {}) {
@@ -6742,23 +6610,7 @@ class PearcordPlatform extends EventEmitter {
return { guildId: gid, requested: n, added, memberCount: (await this.db.find(sharedScope.COLLECTIONS.MEMBERS, { guildId: gid })).length }
}
_compactGuildSyncHealthSlice (guildId) {
const row = this.getGuildSyncHealth(guildId)
if (!row) return null
return {
guildId,
pending: !!row.pending,
syncProgressPct: Number(row.syncProgressPct) || 0,
peers: Number(row.peers) || 0,
messageCount: Number(row.messageCount) || 0,
memberCount: Number(row.memberCount) || 0,
syncMode: row.syncMode || 'gossip',
syncWatermark: row.syncWatermark || null,
lastIngestAt: Number(row.lastIngestAt) || 0,
hostWired: !!row.hostWired,
presenceVectorSize: Number(row.presenceVectorSize) || 0
}
}
_scheduleBroadcastGuildSyncHealthToSettingsMesh (guildId) {
if (!guildId || !this.onboarded || !this.identity?.user?.id) return
@@ -7515,18 +7367,7 @@ class PearcordPlatform extends EventEmitter {
}))
}
_scheduleGuildSyncPushBurst (delays = null, opts = {}) {
const guildId = this.guild?.guild?.id
if (!guildId || this._isGuildSyncPushHalted(guildId)) return
const burst = delays || this._guildSyncBurstDelaysFromRtt()
for (const ms of burst) {
setTimeout(() => {
if (this.guild?.guild?.id !== guildId) return
if (this._isGuildSyncPushHalted(guildId)) return
this._pushGuildSyncToMesh(opts).catch(() => {})
}, ms)
}
}
async _persistGuildMeshHostKey (guildId, hostPublicKey) {
const pk = String(hostPublicKey || '').trim()
@@ -7874,21 +7715,7 @@ class PearcordPlatform extends EventEmitter {
})
}
_scheduleGuildSyncRequestBurst (delays = [0, 600, 1800, 4000, 8000]) {
const guildId = this.guild?.guild?.id
if (!guildId) return
this._guildSyncRequestBackoffGen = (this._guildSyncRequestBackoffGen || 0) + 1
const gen = this._guildSyncRequestBackoffGen
for (let i = 0; i < delays.length; i++) {
const base = delays[i]
const ms = base * (i > 0 ? Math.pow(1.5, i - 1) : 1)
setTimeout(() => {
if (gen !== this._guildSyncRequestBackoffGen) return
if (this.guild?.guild?.id !== guildId) return
this._requestGuildSyncFromHost()
}, Math.round(ms))
}
}
_scheduleGuildMemberSyncRecovery (guildId, hostPublicKey) {
this._guildMemberSyncRecoveryGen = (this._guildMemberSyncRecoveryGen || 0) + 1
+5 -2
View File
@@ -1,6 +1,6 @@
'use strict'
/** Prototype mixins extracted from PearcordPlatform class body (Phases 738744). */
/** Prototype mixins extracted from PearcordPlatform class body (Phases 738745). */
const PLATFORM_RUNTIME_MIXIN_MODULES = [
'./platform-hyperswarm-runtime-mixin',
'./platform-session-startup-mixin',
@@ -17,7 +17,10 @@ const PLATFORM_RUNTIME_MIXIN_MODULES = [
'./platform-member-page-burst-mixin',
'./platform-guild-sync-watermark-mixin',
'./platform-guild-gossip-outbox-mixin',
'./platform-guild-sync-bandwidth-mixin'
'./platform-guild-sync-bandwidth-mixin',
'./platform-guild-sync-health-patch-mixin',
'./platform-guild-sync-gossip-view-mixin',
'./platform-guild-sync-push-schedule-mixin'
]
const PLATFORM_RUNTIME_MIXIN_COUNT = PLATFORM_RUNTIME_MIXIN_MODULES.length