feat(agentctl): channel topic and forum tag mesh journey (Phase 797)

runGuildMeshChannelTopicJourney with activeChannelTopicIncludes and forumTagPaletteMin.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-03 22:32:30 -04:00
co-authored by Cursor
parent fdafa9345d
commit b3728acc96
3 changed files with 67 additions and 0 deletions
+2
View File
@@ -2,6 +2,8 @@
Agent control plane for Pearcord — send the same IPC messages the UI sends, read `view` snapshots, and run scripted journeys against a **live worker** or an in-process **headless** session.
**Phase 797 (v0.8.764):** `runGuildMeshChannelTopicJourney` (topic + forum tags). Bundle: `npm run test:ci-phase797`.
**Phase 796 (v0.8.763):** `runGuildMeshTriplePartitionHealJourney` (3-peer heal + presence). Bundle: `npm run test:ci-phase796`.
**Phase 795 (v0.8.762):** `runGuildMeshTripleMessageJourney` (3-peer message fanout); exports `connectGuildMeshTriple`. Bundle: `npm run test:ci-phase795`.
+14
View File
@@ -93,6 +93,20 @@ function matchView (view, spec) {
if (sec < Number(spec.minSeconds ?? 1)) return false
continue
}
if (key === 'activeChannelTopicIncludes') {
const needle = String(expected || '')
const chId = view?.activeChannelId
const ch = (view?.channels || []).find((c) => c.id === chId)
const topic = ch?.topic || view?.activeChannelSummary?.topic || ''
if (!String(topic).includes(needle)) return false
continue
}
if (key === 'forumTagPaletteMin') {
const min = Number(expected ?? 1)
const n = (view?.forumPaletteTags || []).length
if (n < min) return false
continue
}
if (key === 'typingUsersIncludes') {
const uid = String(expected || '')
if (!(view?.typingUsers || []).includes(uid)) return false
+51
View File
@@ -4986,6 +4986,57 @@ class HeadlessSession {
}
}
/** Phase 797: 2-peer mesh — host topic + forum tags visible on guest. */
async runGuildMeshChannelTopicJourney () {
const { connectGuildMeshPeers } = require('./mesh-helpers')
const topicToken = `mesh797_${Date.now()}`
const tagA = `tag797a_${Date.now()}`
const tagB = `tag797b_${Date.now()}`
const base = path.join(os.tmpdir(), `pearcord-agentctl-chtopic797-${Date.now()}`)
const host = new HeadlessSession({ storagePath: path.join(base, 'host') })
const guest = new HeadlessSession({ storagePath: path.join(base, 'guest') })
await host.start()
await guest.start()
try {
await host.registerUser({ username: 'cthost797', displayName: 'Topic Host 797' })
await host.createGuild({ name: 'Topic Mesh 797', publicListing: false })
await host.wait({ mode: 'guild' }, 45000)
const invite = await host.platform.createInvite().catch(() => null)
const code = invite?.shareCode || invite?.code
if (!code) throw new Error('host invite missing')
await guest.registerUser({ username: 'ctguest797', displayName: 'Topic Guest 797' })
await guest.ipc({ type: 'join-invite', code })
await guest.wait({ mode: 'guild' }, 45000)
const textId = (await host.refreshView()).activeChannelId
if (!textId) throw new Error('active text channel missing')
await guest.ipc({ type: 'select-channel', channelId: textId })
await guest.wait({ activeChannelId: textId }, 30000)
await connectGuildMeshPeers(host.platform, guest.platform, 45000)
await host.platform.setChannelTopic(textId, `Phase 797 ${topicToken}`)
if (typeof host.platform.requestGuildSyncFanout === 'function') {
host.platform.requestGuildSyncFanout()
}
await guest.wait({ activeChannelTopicIncludes: topicToken }, 90000)
const forumCh = await host.createGuildChannel('Forum Topic 797', { type: 'forum' })
await guest.ipc({ type: 'select-channel', channelId: forumCh.id })
await guest.wait({ activeChannelId: forumCh.id }, 30000)
await host.platform.setForumChannelPalette(forumCh.id, [tagA, tagB])
if (typeof host.platform.requestGuildSyncFanout === 'function') {
host.platform.requestGuildSyncFanout()
}
await guest.wait({ forumTagPaletteMin: 2 }, 90000)
const gv = await guest.refreshView()
const palette = gv.forumPaletteTags || []
if (!palette.includes(tagA) || !palette.includes(tagB)) {
throw new Error('guest missing forum tag palette')
}
return { channelId: textId, topicToken, forumChannelId: forumCh.id, palette }
} finally {
await host.close()
await guest.close()
}
}
/** Phase 794: 2-peer mesh — host slowmode visible in guest channelSettings. */
async runGuildMeshChannelSettingsJourney () {
const { connectGuildMeshPeers } = require('./mesh-helpers')