feat(agentctl): 3-peer channel lifecycle create+delete journey (Phase 801)

runGuildMeshTripleChannelLifecycleJourney verifies absent channel on both guests.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-06-03 22:44:23 -04:00
co-authored by Cursor
parent 7e37a30833
commit f8115d0543
2 changed files with 73 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. 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 801 (v0.8.768):** `runGuildMeshTripleChannelLifecycleJourney` (3-peer create + delete). Bundle: `npm run test:ci-phase801`.
**Phase 800 (v0.8.767):** `runGuildMeshChannelLifecycleJourney`, `runGuildMeshTripleChannelCreateJourney`. Bundle: `npm run test:ci-phase800`. **Phase 800 (v0.8.767):** `runGuildMeshChannelLifecycleJourney`, `runGuildMeshTripleChannelCreateJourney`. Bundle: `npm run test:ci-phase800`.
**Phase 799 (v0.8.766):** `runGuildMeshTripleChannelSettingsJourney` (3-peer slowmode). Bundle: `npm run test:ci-phase799`. **Phase 799 (v0.8.766):** `runGuildMeshTripleChannelSettingsJourney` (3-peer slowmode). Bundle: `npm run test:ci-phase799`.
+71
View File
@@ -5165,6 +5165,77 @@ class HeadlessSession {
} }
} }
/** Phase 801: 3-peer mesh — channel create then delete on both guests. */
async runGuildMeshTripleChannelLifecycleJourney () {
const { connectGuildMeshTriple } = require('./mesh-helpers')
const chName = `mesh801t_${Date.now()}`
const base = path.join(os.tmpdir(), `pearcord-agentctl-chtriple801-${Date.now()}`)
const host = new HeadlessSession({ storagePath: path.join(base, 'host') })
const guest1 = new HeadlessSession({ storagePath: path.join(base, 'guest1') })
const guest2 = new HeadlessSession({ storagePath: path.join(base, 'guest2') })
await host.start()
await guest1.start()
await guest2.start()
try {
await host.registerUser({ username: 'clhost801', displayName: 'ChTriple Host 801' })
await host.createGuild({ name: 'ChTriple Life 801', 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 guest1.registerUser({ username: 'clguest801a', displayName: 'ChTriple Guest 801a' })
await guest2.registerUser({ username: 'clguest801b', displayName: 'ChTriple Guest 801b' })
await guest1.ipc({ type: 'join-invite', code })
await guest2.ipc({ type: 'join-invite', code })
await guest1.wait({ mode: 'guild' }, 45000)
await guest2.wait({ mode: 'guild' }, 45000)
await connectGuildMeshTriple(
host.platform,
guest1.platform,
guest2.platform,
50000
)
await host.wait({ meshPeersMin: 1 }, 30000)
await guest1.wait({ meshPeersMin: 1 }, 30000)
await guest2.wait({ meshPeersMin: 1 }, 30000)
const created = await host.createGuildChannel(chName, { type: 'text' })
if (!created?.id) throw new Error('channel create failed')
for (const p of [host.platform, guest1.platform, guest2.platform]) {
if (typeof p.requestGuildSyncFanout === 'function') {
p.requestGuildSyncFanout()
}
}
await guest1.wait({ guildChannelNamed: chName }, 90000)
await guest2.wait({ guildChannelNamed: chName }, 90000)
await host.platform.deleteChannel(created.id)
for (const p of [host.platform, guest1.platform, guest2.platform]) {
if (typeof p.requestGuildSyncFanout === 'function') {
p.requestGuildSyncFanout()
}
}
await guest1.wait({ guildChannelAbsent: chName }, 90000)
await guest2.wait({ guildChannelAbsent: chName }, 90000)
const g1v = await guest1.refreshView()
const g2v = await guest2.refreshView()
if ((g1v.channels || []).some((c) => c.name === chName)) {
throw new Error('guest1 still lists deleted channel')
}
if ((g2v.channels || []).some((c) => c.name === chName)) {
throw new Error('guest2 still lists deleted channel')
}
return {
channelName: chName,
channelId: created.id,
guest1ChannelCount: g1v.channels?.length,
guest2ChannelCount: g2v.channels?.length
}
} finally {
await host.close()
await guest1.close()
await guest2.close()
}
}
/** Phase 800: 3-peer mesh — channel create propagates to both guests. */ /** Phase 800: 3-peer mesh — channel create propagates to both guests. */
async runGuildMeshTripleChannelCreateJourney () { async runGuildMeshTripleChannelCreateJourney () {
const { connectGuildMeshTriple } = require('./mesh-helpers') const { connectGuildMeshTriple } = require('./mesh-helpers')