Phase 451: voice/stage/screen spans with guildId metadata

Add guildId and channelId to voice.join/leave, stage.join/speaker.*, and
screen.start/stop spans and error logs; standardize error field naming.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-23 23:48:10 -04:00
co-authored by Cursor
parent 67b9dffe97
commit 2f847deb7e
2 changed files with 49 additions and 24 deletions
+2
View File
@@ -150,6 +150,8 @@ Primary consumer: `apps/pearcord/index.js` sidecar reading pear-pipe JSON.
**v0.8.413 (Phase 450):** `stageAttachment`/`readAttachmentPreview`/`embed.resolve` spans/errors include `guildId` + `channelId`; `_assertCanParticipate('attach')` for read-only attach gate. Dev-log **attachment-errors** filter: `attachment.stage|read`; **embed-errors**: `embed.resolve`. UI: staging bar + btn-attach `aria-busy`, attach-files permission toast, staging/embed keyboard roving, empty-state hints. Bundle: `npm run test:phase450-attachments-media`.
**v0.8.414 (Phase 451):** `joinVoiceChannel`/`leaveVoiceChannel`/`joinStageChannel`/`requestStageSpeak`/`approveStageSpeaker`/`demoteStageSpeaker`/`startScreenShare`/`stopScreenShare` spans/errors include `guildId` + `channelId`. Dev-log **voice-errors** filter: `voice.join|leave`, `stage.join|speaker.*`, `screen.start|stop`. UI: voice/stage bars + channel list `aria-busy`, stage connect/speak permission toasts, stage approve keyboard, stream popout autofocus. Bundle: `npm run test:phase451-voice-stage`.
**v0.8.402:** `sendMessage`/`editMessage`/`deleteMessage` log `message.*` spans and errors; `toggleReaction` logs `reaction.toggle` span and `reaction.toggle error` on failure.
**v0.8.403:** `stageAttachment`/`readAttachmentPreview` log `attachment.*` spans and errors; `_queueLinkEmbed` logs `embed.resolve` span and `embed.resolve error` on failure.
+47 -24
View File
@@ -6005,8 +6005,10 @@ class PearcordPlatform extends EventEmitter {
}
async startScreenShare (label) {
const guildId = this.guild?.guild?.id || null
const span = this.log.time('screen.start', {
channelId: this.voice?.myChannelId || null
channelId: this.voice?.myChannelId || null,
guildId
})
try {
if (!this.voice?.myChannelId) throw new Error('join a voice channel first')
@@ -6025,12 +6027,13 @@ class PearcordPlatform extends EventEmitter {
targetId: row.channelId
})
this.emit('screen-share', row)
span.end({ channelId: row?.channelId || null })
span.end({ channelId: row?.channelId || null, guildId })
return row
} catch (err) {
this.log.error('screen.start error', {
channelId: this.voice?.myChannelId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err
@@ -6043,8 +6046,10 @@ class PearcordPlatform extends EventEmitter {
}
async stopScreenShare () {
const guildId = this.guild?.guild?.id || null
const span = this.log.time('screen.stop', {
channelId: this.screenShare?.channelId || this.voice?.myChannelId || null
channelId: this.screenShare?.channelId || this.voice?.myChannelId || null,
guildId
})
try {
if (!this.screenShare?.active) {
@@ -6065,12 +6070,13 @@ class PearcordPlatform extends EventEmitter {
}
await this._audit('screen.stop', { guildId: row?.guildId, targetId: row?.channelId })
this.emit('screen-share', row)
span.end({ channelId: row?.channelId || null })
span.end({ channelId: row?.channelId || null, guildId })
return row
} catch (err) {
this.log.error('screen.stop error', {
channelId: this.screenShare?.channelId || this.voice?.myChannelId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err
@@ -6893,7 +6899,8 @@ class PearcordPlatform extends EventEmitter {
}
async joinVoiceChannel (channelId, opts = {}) {
const span = this.log.time('voice.join', { channelId: channelId || null })
const guildId = this.guild?.guild?.id || null
const span = this.log.time('voice.join', { channelId: channelId || null, guildId })
try {
let listenOnly = !!opts.listenOnly
if (this.mode === 'guild') {
@@ -6935,12 +6942,13 @@ class PearcordPlatform extends EventEmitter {
})
this.emit('voice', row)
this.emit('voice-media')
span.end({ channelId, listenOnly })
span.end({ channelId, listenOnly, guildId })
return row
} catch (err) {
this.log.error('voice.join error', {
channelId: channelId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err
@@ -6975,8 +6983,10 @@ class PearcordPlatform extends EventEmitter {
async leaveVoiceChannel () {
const guild = this.guild?.guild
const guildId = guild?.id || null
const span = this.log.time('voice.leave', {
channelId: this.voice?.myChannelId || null
channelId: this.voice?.myChannelId || null,
guildId
})
try {
const leavingId = this.voice?.myChannelId
@@ -7001,13 +7011,15 @@ class PearcordPlatform extends EventEmitter {
if (payload) this.emit('voice', payload)
span.end({
left: !!payload,
channelId: payload?.channelId || null
channelId: payload?.channelId || null,
guildId
})
return payload
} catch (err) {
this.log.error('voice.leave error', {
channelId: this.voice?.myChannelId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err
@@ -7015,7 +7027,8 @@ class PearcordPlatform extends EventEmitter {
}
async joinStageChannel (channelId) {
const span = this.log.time('stage.join', { channelId: channelId || null })
const guildId = this.guild?.guild?.id || null
const span = this.log.time('stage.join', { channelId: channelId || null, guildId })
try {
const guild = this.guild?.guild
const user = this.identity?.user
@@ -7055,12 +7068,13 @@ class PearcordPlatform extends EventEmitter {
this.emit('voice', row)
this.emit('stage', stageRow)
this.emit('voice-media')
span.end({ channelId, role: stageRow?.role || null })
span.end({ channelId, role: stageRow?.role || null, guildId })
return { voice: row, stage: stageRow }
} catch (err) {
this.log.error('stage.join error', {
channelId: channelId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err
@@ -7068,8 +7082,10 @@ class PearcordPlatform extends EventEmitter {
}
async requestStageSpeak () {
const guildId = this.guild?.guild?.id || null
const span = this.log.time('stage.speaker.request', {
channelId: this.voice?.myChannelId || null
channelId: this.voice?.myChannelId || null,
guildId
})
try {
const guild = this.guild?.guild
@@ -7097,12 +7113,13 @@ class PearcordPlatform extends EventEmitter {
meta: { userId: user.id }
})
this.emit('stage', row)
span.end({ channelId: ch.id })
span.end({ channelId: ch.id, guildId })
return row
} catch (err) {
this.log.error('stage.speaker.request error', {
channelId: this.voice?.myChannelId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err
@@ -7110,9 +7127,11 @@ class PearcordPlatform extends EventEmitter {
}
async approveStageSpeaker (targetUserId) {
const guildId = this.guild?.guild?.id || null
const span = this.log.time('stage.speaker.approve', {
channelId: this.voice?.myChannelId || null,
userId: targetUserId || null
userId: targetUserId || null,
guildId
})
try {
const guild = this.guild?.guild
@@ -7142,13 +7161,14 @@ class PearcordPlatform extends EventEmitter {
await this.setVoiceMute({ muted: false, deafened: false })
}
this.emit('stage', row)
span.end({ channelId, userId: targetUserId })
span.end({ channelId, userId: targetUserId, guildId })
return row
} catch (err) {
this.log.error('stage.speaker.approve error', {
channelId: this.voice?.myChannelId || null,
userId: targetUserId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err
@@ -7156,9 +7176,11 @@ class PearcordPlatform extends EventEmitter {
}
async demoteStageSpeaker (targetUserId) {
const guildId = this.guild?.guild?.id || null
const span = this.log.time('stage.speaker.demote', {
channelId: this.voice?.myChannelId || null,
userId: targetUserId || null
userId: targetUserId || null,
guildId
})
try {
const guild = this.guild?.guild
@@ -7188,13 +7210,14 @@ class PearcordPlatform extends EventEmitter {
await this.setVoiceMute({ muted: true, deafened: false })
}
this.emit('stage', row)
span.end({ channelId, userId: targetUserId })
span.end({ channelId, userId: targetUserId, guildId })
return row
} catch (err) {
this.log.error('stage.speaker.demote error', {
channelId: this.voice?.myChannelId || null,
userId: targetUserId || null,
err: err?.message || String(err)
guildId,
error: err?.message || String(err)
})
span.fail(err)
throw err