feat(platform): Phase 878 gossip RPC pull helpers + view diagnostics (v0.8.845)

Non-breaking mesh hardening: pickFirstGuildRpcResponse with shared validation
predicates for audit/digest RPC pulls; buildGuildGossipRpcDiagnosticsSnapshot
on platform view; unify pull-path viaRpc via markRpcResponse across mesh view
and fetch helpers. Default gossip v1 unchanged; fleet v2 cutover deferred.

Tests: test:ci-phase878 (boot gate, unit, view snapshot, method maps, live digest RPC).
Docs: PLATFORM_ROADMAP, PROTOMUX_RPC_MIGRATION, AUTOMATED_TESTING, release notes.
This commit is contained in:
Raven Scott
2026-06-04 18:09:20 -04:00
parent 2910aefedb
commit 9bba800893
7 changed files with 55 additions and 22 deletions
+2
View File
@@ -92,6 +92,8 @@ Application facade: one `PearcordPlatform` class that wires identity, database,
**Phase 822 (v0.8.789):** Triple-peer topology via `guild-mesh-topology` + `getMeshStabilityStats`. Bundle: `npm run test:ci-phase822`.
**Phase 878 (v0.8.845):** Gossip RPC pull response helpers (`pickFirstGuildRpcResponse`, validation predicates) + view diagnostics (`buildGuildGossipRpcDiagnosticsSnapshot`). Bundle: `npm run test:ci-phase878`.
**Phase 877 (v0.8.844):** View snapshot RPC wire diagnostics via `buildRpcWireViewSnapshot()`; guild sync/member page handlers use shared `markRpcResponse`. Bundle: `npm run test:ci-phase877`.
**Phase 876 (v0.8.843):** Shared `gossip-rpc-pull.js` + `gossip-rpc-handler-map.js` dedupe for all guild gossip RPC pull paths (zero behavior change). Bundle: `npm run test:ci-phase876`.
+29 -1
View File
@@ -90,6 +90,20 @@ function markRpcResponse (res) {
return res
}
/** First matching guild gossip RPC pull response (Phase 878). */
function pickFirstGuildRpcResponse (responses, predicate) {
if (!Array.isArray(responses) || typeof predicate !== 'function') return null
return responses.find((r) => r && predicate(r)) || null
}
function isValidAuditExportArchiveRpcResponse (r) {
return Array.isArray(r?.entries) && r.entries.length > 0
}
function isValidAutomationDigestSnapshotRpcResponse (r) {
return typeof r?.body === 'string' && r.body.length > 0
}
/** Dev/settings snapshot of protomux-rpc opt-in flags (Phase 877). */
function buildRpcWireViewSnapshot () {
const {
@@ -108,6 +122,16 @@ function buildRpcWireViewSnapshot () {
}
}
/** Guild gossip RPC handler diagnostics for platform view (Phase 878). */
function buildGuildGossipRpcDiagnosticsSnapshot () {
const { listGuildGossipRpcRequestMethodKeys } = require('./gossip-rpc-handler-map')
const methods = listGuildGossipRpcRequestMethodKeys()
return {
guildGossipRpcHandlerCount: methods.length,
guildGossipRpcRequestMethods: methods
}
}
module.exports = {
meshPeerIdHex,
guildRpcTimeoutsMs,
@@ -117,5 +141,9 @@ module.exports = {
requestGuildGossipRpcFromPeers,
matchesGuildRpcTargetMember,
markRpcResponse,
buildRpcWireViewSnapshot
pickFirstGuildRpcResponse,
isValidAuditExportArchiveRpcResponse,
isValidAutomationDigestSnapshotRpcResponse,
buildRpcWireViewSnapshot,
buildGuildGossipRpcDiagnosticsSnapshot
}
@@ -9,7 +9,9 @@ const {
guildRpcTimeoutsMs,
resolveGuildGossipRpcPeerIds,
prepareGuildGossipRpcSession,
requestGuildGossipRpcFromPeers
requestGuildGossipRpcFromPeers,
pickFirstGuildRpcResponse,
isValidAuditExportArchiveRpcResponse
} = require('../../../gossip-rpc-pull')
const platformAuditArchiveRpcMixin = {
@@ -69,7 +71,7 @@ const platformAuditArchiveRpcMixin = {
rpcMs,
wireMs
})
const hit = responses.find((r) => r && Array.isArray(r.entries) && r.entries.length)
const hit = pickFirstGuildRpcResponse(responses, isValidAuditExportArchiveRpcResponse)
return hit || null
}
}
@@ -27,6 +27,7 @@ const {
buildActivityFeed, enrichActivityWithAttachments, IPC_CONTRACT_VERSION, Hyperswarm,
id, now, guildTopic
} = require('../../../platform-class-imports')
const { markRpcResponse } = require('../../../gossip-rpc-pull')
/** Phase 756 — audit log & automation digest export */
@@ -482,15 +483,14 @@ async _fetchAutomationDigestSnapshotFromMeshOnce (snapshotId, opts = {}) {
const rpcSnap = await this._tryFetchAutomationDigestSnapshotFromMeshRpc(snapshotId, opts)
if (rpcSnap?.body?.length) {
await this.deliveryReceipts.ingestAutomationDigestExportSnapshot(rpcSnap).catch(() => {})
return {
return markRpcResponse({
snapshotId: rpcSnap.id || snapshotId,
format: rpcSnap.format,
body: rpcSnap.body,
summaryLines: rpcSnap.summaryLines,
exportedAt: rpcSnap.exportedAt,
fetchAttempt: (Number(opts.attempt) || 0) + 1,
viaRpc: true
}
fetchAttempt: (Number(opts.attempt) || 0) + 1
})
}
}
const timeoutMs = Math.min(12000, Math.max(800, Number(opts.timeoutMs) || 3500))
@@ -593,11 +593,10 @@ async _fetchAuditExportArchiveFromMeshOnce (archiveId, opts = {}) {
if (rpcArch?.entries?.length) {
await this.deliveryReceipts.ingestAuditExportArchive(rpcArch).catch(() => {})
const out = await this.exportAuditExportArchive(rpcArch.id || archiveId, opts)
return {
return markRpcResponse({
...out,
fetchAttempt: (Number(opts.attempt) || 0) + 1,
viaRpc: true
}
fetchAttempt: (Number(opts.attempt) || 0) + 1
})
}
}
const timeoutMs = Math.min(12000, Math.max(800, Number(opts.timeoutMs) || 3500))
@@ -8,7 +8,9 @@ const {
guildRpcTimeoutsMs,
resolveGuildGossipRpcPeerIds,
prepareGuildGossipRpcSession,
requestGuildGossipRpcFromPeers
requestGuildGossipRpcFromPeers,
pickFirstGuildRpcResponse,
isValidAutomationDigestSnapshotRpcResponse
} = require('../../../gossip-rpc-pull')
const platformAutomationDigestSnapshotRpcMixin = {
@@ -70,7 +72,7 @@ const platformAutomationDigestSnapshotRpcMixin = {
rpcMs,
wireMs
})
const hit = responses.find((r) => r && typeof r.body === 'string' && r.body.length)
const hit = pickFirstGuildRpcResponse(responses, isValidAutomationDigestSnapshotRpcResponse)
return hit || null
}
}
@@ -5,7 +5,8 @@ const sharedScope = require('../../../platform-pearcord-shared-imports')
const {
guildRpcTimeoutsMs,
resolveGuildGossipRpcHostPeerId,
prepareGuildGossipRpcSession
prepareGuildGossipRpcSession,
markRpcResponse
} = require('../../../gossip-rpc-pull')
const platformMeshViewMixin = {
@@ -37,13 +38,12 @@ const platformMeshViewMixin = {
)
if (!page?.guildId) return null
const added = await this._ingestMemberPage(page)
return {
return markRpcResponse({
requested: true,
viaRpc: true,
offset: page.offset,
memberCount: page.members?.length || 0,
added
}
})
},
async _tryGuildSyncRequestRpc (channelId) {
@@ -79,12 +79,11 @@ const platformMeshViewMixin = {
)
if (!bundle?.guildId) return null
await this._ingestGuildSync(bundle)
return {
return markRpcResponse({
requested: true,
viaRpc: true,
peerCount: 1,
hostPublicKey: hostPk
}
})
},
_fanoutGuildSyncRequestBroadcast (channelId) {
+3 -2
View File
@@ -28,7 +28,7 @@ const {
id, now, guildTopic
} = require('../../../platform-class-imports')
const { buildSettingsHubView } = require('pearcord-shared/settings-taxonomy')
const { buildRpcWireViewSnapshot } = require('../../../gossip-rpc-pull')
const { buildRpcWireViewSnapshot, buildGuildGossipRpcDiagnosticsSnapshot } = require('../../../gossip-rpc-pull')
/** Phase 756 — IPC view snapshot */
@@ -2906,7 +2906,8 @@ async view (opts = {}) {
: null,
readReceiptSyncRows: await this._readReceiptSyncRowsForView(this.guild?.guild?.id),
sparseAckSyncRows: this._sparseAckSyncRowsForView(this.guild?.guild?.id),
...buildRpcWireViewSnapshot()
...buildRpcWireViewSnapshot(),
...buildGuildGossipRpcDiagnosticsSnapshot()
}
},