refactor(platform): Phase 730 mixin manifest and gossip validation DRY

Introduce platform-mixin-assign-manifest.js (59 rows, same assign order) and
manifest-driven apply-platform-mixins loop. Add json-export-gossip-alignment-
validate.js, platform-ipc-contract.js; digest-json uses per-entry gossip keys.
No observable behavior or mesh semantics changes.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-03 10:05:49 -04:00
co-authored by Cursor
parent 4ca8d53553
commit 59314420af
7 changed files with 145 additions and 124 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 730 (v0.8.706):** `platform-mixin-assign-manifest.js` drives 59 prototype mixin assigns; `json-export-gossip-alignment-validate.js` + registry-backed smokes; `platform-ipc-contract.js`; digest-json per-entry gossip keys. Bundle: `npm run test:ci-phase730`.
**Phase 729 (v0.8.705):** Dual-heal legacy json mixins repaired (voice/stage/screen gossip keys + heal contexts); per-entry `keysField`/`initMethod` on 14 dual-heal files; `json-export-gossip-registry.js` alignment tables; `platform-hyperdb-sync.js` extracted from index. Bundle: `npm run test:ci-phase729`.
**Phase 728 (v0.8.704):** Combined delegate json mixins align gossip `keysField` with dedicated mixins; `platform-message-enrichment.js` + `platform-delivery-receipts-imports.js` extracted from index. Bundle: `npm run test:ci-phase728`.
+7 -120
View File
@@ -1,128 +1,15 @@
'use strict'
const { PLATFORM_MIXIN_ASSIGNMENTS } = require('./platform-mixin-assign-manifest')
/**
* Side-effect mixin registration for PearcordPlatform (preserves assign order from index.js).
*/
function applyPlatformMixins (PearcordPlatform) {
const { pollSchedulingMixin } = require('./polls-scheduling')
const { notificationsActivityMixin } = require('./notifications-activity')
const { userSettingsMixin } = require('./user-settings')
const { moderationMixin } = require('./moderation')
const { invitesDiscoveryMixin } = require('./invites-discovery')
const { threadsForumMixin } = require('./threads-forum')
const { announcementsMixin } = require('./announcements-mixin')
const { permissionsMixin } = require('./permissions-mixin')
const { memberRolesMixin } = require('./member-roles-mixin')
const { slashMixin } = require('./slash-mixin')
const { botsMixin } = require('./bots-mixin')
const { webhooksMixin } = require('./webhooks-mixin')
const { automationMixin } = require('./automation-mixin')
const { workersMixin } = require('./workers-mixin')
const { deliveryMixin } = require('./delivery-mixin')
const { healthMixin } = require('./health-mixin')
const { auditJsonMixin } = require('./audit-json-mixin')
const { digestJsonMixin } = require('./digest-json-mixin')
const { relayJsonMixin } = require('./relay-json-mixin')
const { workerJsonMixin } = require('./worker-json-mixin')
const { botRegistryJsonMixin } = require('./bot-registry-json-mixin')
const { slashJsonMixin } = require('./slash-json-mixin')
const { oauthJsonMixin } = require('./oauth-json-mixin')
const { inviteJsonMixin } = require('./invite-json-mixin')
const { permissionJsonMixin } = require('./permission-json-mixin')
const { emojiJsonMixin } = require('./emoji-json-mixin')
const { memberJsonMixin } = require('./member-json-mixin')
const { banJsonMixin } = require('./ban-json-mixin')
const { pollJsonMixin } = require('./poll-json-mixin')
const { pinJsonMixin } = require('./pin-json-mixin')
const { threadJsonMixin } = require('./thread-json-mixin')
const { stageJsonMixin } = require('./stage-json-mixin')
const { voiceJsonMixin } = require('./voice-json-mixin')
const { screenJsonMixin } = require('./screen-json-mixin')
const { presenceJsonMixin } = require('./presence-json-mixin')
const { notificationJsonMixin } = require('./notification-json-mixin')
const { statusJsonMixin } = require('./status-json-mixin')
const { activityJsonMixin } = require('./activity-json-mixin')
const { sessionJsonMixin } = require('./session-json-mixin')
const { deviceJsonMixin } = require('./device-json-mixin')
const { discoveryJsonMixin } = require('./discovery-json-mixin')
const { federationJsonMixin } = require('./federation-json-mixin')
const { meshJsonMixin } = require('./mesh-json-mixin')
const { multiGuildJsonMixin } = require('./multi-guild-json-mixin')
const { partitionHealJsonMixin } = require('./partition-heal-json-mixin')
const { channelFollowJsonMixin } = require('./channel-follow-json-mixin')
const { guildWidgetJsonMixin } = require('./guild-widget-json-mixin')
const { readStateJsonMixin } = require('./read-state-json-mixin')
const { webhookJsonMixin } = require('./webhook-json-mixin')
const { vanityUrlJsonMixin } = require('./vanity-url-json-mixin')
const { effectivePermissionJsonMixin } = require('./effective-permission-json-mixin')
const { inviteLinkJsonMixin } = require('./invite-link-json-mixin')
const { roleOverrideJsonMixin } = require('./role-override-json-mixin')
const { oauthGrantJsonMixin } = require('./oauth-grant-json-mixin')
const { oauthInstallTokenJsonMixin } = require('./oauth-install-token-json-mixin')
const { slashRegistryJsonMixin } = require('./slash-registry-json-mixin')
const { slashInvokeAuditJsonMixin } = require('./slash-invoke-audit-json-mixin')
const { workerReleaseJsonMixin } = require('./worker-release-json-mixin')
const { integrationManifestJsonMixin } = require('./integration-manifest-json-mixin')
Object.assign(PearcordPlatform.prototype, pollSchedulingMixin)
Object.assign(PearcordPlatform.prototype, notificationsActivityMixin)
Object.assign(PearcordPlatform.prototype, userSettingsMixin)
Object.assign(PearcordPlatform.prototype, moderationMixin)
Object.assign(PearcordPlatform.prototype, invitesDiscoveryMixin)
Object.assign(PearcordPlatform.prototype, threadsForumMixin)
Object.assign(PearcordPlatform.prototype, announcementsMixin)
Object.assign(PearcordPlatform.prototype, permissionsMixin)
Object.assign(PearcordPlatform.prototype, memberRolesMixin)
Object.assign(PearcordPlatform.prototype, slashMixin)
Object.assign(PearcordPlatform.prototype, botsMixin)
Object.assign(PearcordPlatform.prototype, webhooksMixin)
Object.assign(PearcordPlatform.prototype, automationMixin)
Object.assign(PearcordPlatform.prototype, workersMixin)
Object.assign(PearcordPlatform.prototype, deliveryMixin)
Object.assign(PearcordPlatform.prototype, healthMixin)
Object.assign(PearcordPlatform.prototype, auditJsonMixin)
Object.assign(PearcordPlatform.prototype, digestJsonMixin)
Object.assign(PearcordPlatform.prototype, relayJsonMixin)
Object.assign(PearcordPlatform.prototype, workerJsonMixin)
Object.assign(PearcordPlatform.prototype, botRegistryJsonMixin)
Object.assign(PearcordPlatform.prototype, slashJsonMixin)
Object.assign(PearcordPlatform.prototype, oauthJsonMixin)
Object.assign(PearcordPlatform.prototype, inviteJsonMixin)
Object.assign(PearcordPlatform.prototype, permissionJsonMixin)
Object.assign(PearcordPlatform.prototype, emojiJsonMixin)
Object.assign(PearcordPlatform.prototype, memberJsonMixin)
Object.assign(PearcordPlatform.prototype, banJsonMixin)
Object.assign(PearcordPlatform.prototype, pollJsonMixin)
Object.assign(PearcordPlatform.prototype, pinJsonMixin)
Object.assign(PearcordPlatform.prototype, threadJsonMixin)
Object.assign(PearcordPlatform.prototype, stageJsonMixin)
Object.assign(PearcordPlatform.prototype, voiceJsonMixin)
Object.assign(PearcordPlatform.prototype, screenJsonMixin)
Object.assign(PearcordPlatform.prototype, presenceJsonMixin)
Object.assign(PearcordPlatform.prototype, notificationJsonMixin)
Object.assign(PearcordPlatform.prototype, statusJsonMixin)
Object.assign(PearcordPlatform.prototype, activityJsonMixin)
Object.assign(PearcordPlatform.prototype, sessionJsonMixin)
Object.assign(PearcordPlatform.prototype, deviceJsonMixin)
Object.assign(PearcordPlatform.prototype, discoveryJsonMixin)
Object.assign(PearcordPlatform.prototype, federationJsonMixin)
Object.assign(PearcordPlatform.prototype, meshJsonMixin)
Object.assign(PearcordPlatform.prototype, multiGuildJsonMixin)
Object.assign(PearcordPlatform.prototype, partitionHealJsonMixin)
Object.assign(PearcordPlatform.prototype, channelFollowJsonMixin)
Object.assign(PearcordPlatform.prototype, guildWidgetJsonMixin)
Object.assign(PearcordPlatform.prototype, readStateJsonMixin)
Object.assign(PearcordPlatform.prototype, webhookJsonMixin)
Object.assign(PearcordPlatform.prototype, vanityUrlJsonMixin)
Object.assign(PearcordPlatform.prototype, effectivePermissionJsonMixin)
Object.assign(PearcordPlatform.prototype, inviteLinkJsonMixin)
Object.assign(PearcordPlatform.prototype, roleOverrideJsonMixin)
Object.assign(PearcordPlatform.prototype, oauthGrantJsonMixin)
Object.assign(PearcordPlatform.prototype, oauthInstallTokenJsonMixin)
Object.assign(PearcordPlatform.prototype, slashRegistryJsonMixin)
Object.assign(PearcordPlatform.prototype, slashInvokeAuditJsonMixin)
Object.assign(PearcordPlatform.prototype, workerReleaseJsonMixin)
Object.assign(PearcordPlatform.prototype, integrationManifestJsonMixin)
for (const row of PLATFORM_MIXIN_ASSIGNMENTS) {
const mixin = require(row.module)[row.export]
Object.assign(PearcordPlatform.prototype, mixin)
}
}
module.exports = { applyPlatformMixins }
module.exports = { applyPlatformMixins, PLATFORM_MIXIN_ASSIGNMENTS }
+6 -3
View File
@@ -3,10 +3,13 @@
const { createJsonExportDualHealMixin } = require('pearcord-json-export-mixin')
const digestJsonMixin = createJsonExportDualHealMixin({
keysField: '_hookFailureDigestJsonGossipKeys',
initMethod: '_initDigestJsonMixinState',
gossipEntries: [
{ method: '_shouldGossipHookFailureDigestJson', gossipHashPrefix: '' },
{
method: '_shouldGossipHookFailureDigestJson',
gossipHashPrefix: '',
keysField: '_hookFailureDigestJsonGossipKeys',
initMethod: '_initDigestJsonMixinState'
}
],
heals: [
{
+1 -1
View File
@@ -365,7 +365,7 @@ const {
} = require('./view-integrity-phase409')
const { createTopicMergeCounters } = require('pearcord-channel-meta/topic-merge-counters')
const { sanitizeAutomationEventPayload } = require('pearcord-automation-export')
const IPC_CONTRACT_VERSION = 1
const { IPC_CONTRACT_VERSION } = require('./platform-ipc-contract')
const {
normalizeServerFolders,
buildServerRailLayout,
+54
View File
@@ -0,0 +1,54 @@
'use strict'
/**
* Shared static checks for combined vs dedicated JSON export gossip alignment.
* Used by app smokes; no runtime platform dependency.
*/
function validateGossipAlignmentRow (row, combinedSrc, dedicatedSrc) {
if (!combinedSrc.includes(row.keysField)) {
throw new Error(`${row.combined} missing keysField ${row.keysField}`)
}
if (!combinedSrc.includes(row.initMethod)) {
throw new Error(`${row.combined} missing initMethod ${row.initMethod}`)
}
if (!dedicatedSrc.includes(`keysField: '${row.keysField}'`)) {
throw new Error(`${row.dedicated} keysField mismatch vs ${row.combined}`)
}
if (row.gossipHashPrefix && !combinedSrc.includes(`gossipHashPrefix: '${row.gossipHashPrefix}'`)) {
throw new Error(`${row.combined} missing gossipHashPrefix ${row.gossipHashPrefix}`)
}
if (row.method && !combinedSrc.includes(row.method)) {
throw new Error(`${row.combined} missing gossip method ${row.method}`)
}
}
function validateDualHealPerEntryGossipKeys (src, fileName, opts = {}) {
const minEntries = opts.minEntries ?? 2
if (!src.includes('createJsonExportDualHealMixin')) return
const block = src.match(/gossipEntries:\s*\[([\s\S]*?)\]\s*,\s*heals:/)
if (!block) {
throw new Error(`${fileName} dual-heal missing gossipEntries block`)
}
const entries = block[1]
const entryCount = (entries.match(/method:\s*'/g) || []).length
if (entryCount < minEntries) {
throw new Error(`${fileName} expected at least ${minEntries} gossip entries, got ${entryCount}`)
}
const keysCount = (entries.match(/keysField:\s*'/g) || []).length
if (keysCount < entryCount) {
throw new Error(`${fileName} expected per-entry keysField on all gossip rows (${keysCount}/${entryCount})`)
}
const initCount = (entries.match(/initMethod:\s*'/g) || []).length
if (initCount < entryCount) {
throw new Error(`${fileName} expected per-entry initMethod on all gossip rows (${initCount}/${entryCount})`)
}
const cfgHead = src.match(/createJsonExportDualHealMixin\(\{\s*([\s\S]*?)\n\s*gossipEntries:/)
if (cfgHead && /keysField\s*:/.test(cfgHead[1])) {
throw new Error(`${fileName} must not use top-level keysField on dual-heal factory`)
}
}
module.exports = {
validateGossipAlignmentRow,
validateDualHealPerEntryGossipKeys
}
+6
View File
@@ -0,0 +1,6 @@
'use strict'
/** IPC envelope version surfaced to companion and UI (Phase 730 extract). */
const IPC_CONTRACT_VERSION = 1
module.exports = { IPC_CONTRACT_VERSION }
+69
View File
@@ -0,0 +1,69 @@
'use strict'
/**
* Ordered PearcordPlatform prototype mixin registration (Phase 730).
* Preserves assign order from index.js / apply-platform-mixins (Phase 727).
*/
const PLATFORM_MIXIN_ASSIGNMENTS = [
{ module: './polls-scheduling', export: 'pollSchedulingMixin' },
{ module: './notifications-activity', export: 'notificationsActivityMixin' },
{ module: './user-settings', export: 'userSettingsMixin' },
{ module: './moderation', export: 'moderationMixin' },
{ module: './invites-discovery', export: 'invitesDiscoveryMixin' },
{ module: './threads-forum', export: 'threadsForumMixin' },
{ module: './announcements-mixin', export: 'announcementsMixin' },
{ module: './permissions-mixin', export: 'permissionsMixin' },
{ module: './member-roles-mixin', export: 'memberRolesMixin' },
{ module: './slash-mixin', export: 'slashMixin' },
{ module: './bots-mixin', export: 'botsMixin' },
{ module: './webhooks-mixin', export: 'webhooksMixin' },
{ module: './automation-mixin', export: 'automationMixin' },
{ module: './workers-mixin', export: 'workersMixin' },
{ module: './delivery-mixin', export: 'deliveryMixin' },
{ module: './health-mixin', export: 'healthMixin' },
{ module: './audit-json-mixin', export: 'auditJsonMixin' },
{ module: './digest-json-mixin', export: 'digestJsonMixin' },
{ module: './relay-json-mixin', export: 'relayJsonMixin' },
{ module: './worker-json-mixin', export: 'workerJsonMixin' },
{ module: './bot-registry-json-mixin', export: 'botRegistryJsonMixin' },
{ module: './slash-json-mixin', export: 'slashJsonMixin' },
{ module: './oauth-json-mixin', export: 'oauthJsonMixin' },
{ module: './invite-json-mixin', export: 'inviteJsonMixin' },
{ module: './permission-json-mixin', export: 'permissionJsonMixin' },
{ module: './emoji-json-mixin', export: 'emojiJsonMixin' },
{ module: './member-json-mixin', export: 'memberJsonMixin' },
{ module: './ban-json-mixin', export: 'banJsonMixin' },
{ module: './poll-json-mixin', export: 'pollJsonMixin' },
{ module: './pin-json-mixin', export: 'pinJsonMixin' },
{ module: './thread-json-mixin', export: 'threadJsonMixin' },
{ module: './stage-json-mixin', export: 'stageJsonMixin' },
{ module: './voice-json-mixin', export: 'voiceJsonMixin' },
{ module: './screen-json-mixin', export: 'screenJsonMixin' },
{ module: './presence-json-mixin', export: 'presenceJsonMixin' },
{ module: './notification-json-mixin', export: 'notificationJsonMixin' },
{ module: './status-json-mixin', export: 'statusJsonMixin' },
{ module: './activity-json-mixin', export: 'activityJsonMixin' },
{ module: './session-json-mixin', export: 'sessionJsonMixin' },
{ module: './device-json-mixin', export: 'deviceJsonMixin' },
{ module: './discovery-json-mixin', export: 'discoveryJsonMixin' },
{ module: './federation-json-mixin', export: 'federationJsonMixin' },
{ module: './mesh-json-mixin', export: 'meshJsonMixin' },
{ module: './multi-guild-json-mixin', export: 'multiGuildJsonMixin' },
{ module: './partition-heal-json-mixin', export: 'partitionHealJsonMixin' },
{ module: './channel-follow-json-mixin', export: 'channelFollowJsonMixin' },
{ module: './guild-widget-json-mixin', export: 'guildWidgetJsonMixin' },
{ module: './read-state-json-mixin', export: 'readStateJsonMixin' },
{ module: './webhook-json-mixin', export: 'webhookJsonMixin' },
{ module: './vanity-url-json-mixin', export: 'vanityUrlJsonMixin' },
{ module: './effective-permission-json-mixin', export: 'effectivePermissionJsonMixin' },
{ module: './invite-link-json-mixin', export: 'inviteLinkJsonMixin' },
{ module: './role-override-json-mixin', export: 'roleOverrideJsonMixin' },
{ module: './oauth-grant-json-mixin', export: 'oauthGrantJsonMixin' },
{ module: './oauth-install-token-json-mixin', export: 'oauthInstallTokenJsonMixin' },
{ module: './slash-registry-json-mixin', export: 'slashRegistryJsonMixin' },
{ module: './slash-invoke-audit-json-mixin', export: 'slashInvokeAuditJsonMixin' },
{ module: './worker-release-json-mixin', export: 'workerReleaseJsonMixin' },
{ module: './integration-manifest-json-mixin', export: 'integrationManifestJsonMixin' }
]
module.exports = { PLATFORM_MIXIN_ASSIGNMENTS }