feat(mesh): peer retry on guild create and wire/outbox hardening (v0.8.747)

Schedule mesh peer retry when create finishes with no peers; gossip outbox and
wire mixin tweaks for join reliability during guild loading.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-03 21:04:38 -04:00
co-authored by Cursor
parent 66160bbc53
commit 2792be67c8
4 changed files with 50 additions and 20 deletions
+2
View File
@@ -2,6 +2,8 @@
Application facade: one `PearcordPlatform` class that wires identity, database, guild mesh, DMs, invites, voice, discovery, bots, and dozens of feature modules for the Pearcord desktop sidecar and companion. **Mixin sources:** [`mixins/README.md`](mixins/README.md) — `domain/`, `json-export/`, `runtime/{core,mesh,guild-sync,search-discovery,partition-heal,view,voice-dm,features}/`. Architecture: [PLATFORM_MIXINS.md](../../docs/PLATFORM_MIXINS.md). Regenerate after manifest edits: `cd apps/pearcord && npm run regenerate:platform-mixins`. OTA prestage recursively verifies symbols under `mixins/` — [RELEASE.md](../../docs/RELEASE.md#prestage-sync-file-deps).
**Phase 780 (v0.8.747):** Guild mesh loading sync — peer retry on `createGuild` with 0 peers; `guild-loading` structural push path (worker + ui-flow). Bundle: `npm run test:ci-phase780`.
**Phase 779 (v0.8.746):** Effective permissions deep link `memberId` + `effectivePermFocusMemberId`; inspector cross-link to channel perms. Bundle: `npm run test:ci-phase779`.
**Phase 778 (v0.8.745):** Effective permissions deep link role focus — `navigateDeepLink` returns `effectivePermFocusRoleId` from `?effective=1&roleId=`. Bundle: `npm run test:ci-phase778`.
@@ -630,6 +630,16 @@ async createGuild ({ name, publicListing = true, templateId = null } = {}) {
bounded: true,
joinMeshCapMs: createCaps[0]
})
this._scheduleProfileGossipBurst()
if ((this.guild.peers?.size ?? 0) === 0) {
this._scheduleGuildMeshPeerRetry(result.guild.id)
} else {
this._maybeEvictStaleGuildMeshPeers(result.guild.id, 'guild-create')
}
this._startGuildMeshStalePeerSweep(result.guild.id)
if (user.id === result.guild.ownerId) {
void this._getGuildReplicator(result.guild.id).catch(() => {})
}
await this._initGuildVoice(result.guild.id)
this.messages = new PearcordMessage({ authorId: user.id, db: this.db })
await this.messages.ready()
@@ -1,8 +1,23 @@
'use strict'
const { ensureGuildWireChannels } = require('pearcord-guild/mesh')
const { wireReady } = require('pearcord-drive/mux-wire')
const swarmScope = require('../../../platform-swarm-manager-imports')
const platformGuildGossipOutboxMixin = {
async _ensureGuildGossipWireReady (timeoutMs) {
if (!this.guild?._channels) return false
ensureGuildWireChannels(this.guild)
const wireMs =
timeoutMs ??
(Number(process.env.PEARCORD_GUILD_WIRE_READY_MS) || 4000)
const sessions = [...this.guild._channels.values()]
if (!sessions.length) return false
const results = await Promise.all(
sessions.map((session) => wireReady(session, wireMs).catch(() => false))
)
return results.some(Boolean)
},
async _guildGossipOrQueue (label, sendFn) {
if (!this.guild || typeof sendFn !== 'function') return null
const peers = this.guild.peers?.size ?? 0
@@ -343,7 +343,6 @@ _wireGuild (guildInstance) {
40,
Math.min(800, Date.now() - joinedAt)
)
void this._flushGuildGossipOutbox({ reason: 'peer-join' }).catch(() => {})
if (gid && peerId) {
this._trackGuildTopicPeer(gid, peerId, 'join')
this._touchGuildMeshPeerSeen(gid, peerId, 'peer-join')
@@ -366,9 +365,6 @@ _wireGuild (guildInstance) {
meshPeerCount: this.guild?.peers?.size ?? 0
})
if (peerId) this._scheduleMemberEnsureFromMeshPeer(peerId, gid)
if (this.guild?.guild?.ownerId === this.identity?.user?.id) {
this._schedulePeerMemberIdentifyRequest(gid, peerId)
}
}
const conn = peerId ? this.guild?.peers?.get(peerId) : null
if (gid && conn) {
@@ -384,24 +380,31 @@ _wireGuild (guildInstance) {
})
.catch(() => {})
}
void (async () => {
await this._ensureGuildGossipWireReady().catch(() => false)
await this._flushGuildGossipOutbox({ reason: 'peer-join' }).catch(() => {})
if (gid && peerId && this.guild?.guild?.ownerId === this.identity?.user?.id) {
this._schedulePeerMemberIdentifyRequest(gid, peerId)
}
this._scheduleProfileGossipBurst()
if (this.guild?.guild?.ownerId === this.identity?.user?.id) {
this._guildSyncPushHalted.delete(this.guild.guild.id)
this._scheduleGuildSyncPushBurst([250, 1000, 2500, 5000])
} else {
const joinGuildId = this.guild?.guild?.id
const joinUserId = this.identity?.user?.id
if (joinGuildId && joinUserId) {
await this._gossipMemberJoinForUser(joinGuildId, joinUserId).catch(() => {})
void this._nudgeGuildMemberJoinGossip(joinGuildId, joinUserId)
}
this._requestGuildSyncFromHost()
this._scheduleGuildSyncRequestBurst([400, 1500, 3500])
}
this.emit('member')
this.emit('presence')
})().catch(() => {})
}
if (type !== 'join') return
this._scheduleProfileGossipBurst()
if (this.guild?.guild?.ownerId === this.identity?.user?.id) {
this._guildSyncPushHalted.delete(this.guild.guild.id)
this._scheduleGuildSyncPushBurst([250, 1000, 2500, 5000])
} else {
const joinGuildId = this.guild?.guild?.id
const joinUserId = this.identity?.user?.id
if (joinGuildId && joinUserId) {
void this._gossipMemberJoinForUser(joinGuildId, joinUserId).catch(() => {})
void this._nudgeGuildMemberJoinGossip(joinGuildId, joinUserId)
}
this._requestGuildSyncFromHost()
this._scheduleGuildSyncRequestBurst([400, 1500, 3500])
}
this.emit('member')
this.emit('presence')
})
guildInstance.on('attachment', (p) => {
this.attachments?.ingestGossip(p).catch(() => {})