Phase 821: runGuildMeshTripleAckWatermarkJourney (v0.8.788).
Adds guildSyncWatermarkPresent and guildSyncAckPeersMin matchers for triple-peer ACK watermark fanout contract after mesh message delta. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -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 821 (v0.8.788):** `runGuildMeshTripleAckWatermarkJourney` (3-peer ACK watermark). Bundle: `npm run test:ci-phase821`.
|
||||
|
||||
**Phase 820 (v0.8.787):** `runGuildMeshTripleMemberRosterCompleteJourney` (3-peer roster sync complete). Bundle: `npm run test:ci-phase820`.
|
||||
|
||||
**Phase 819 (v0.8.786):** `runGuildMeshTripleSyncPendingJourney` (3-peer sync pending & outbox). Bundle: `npm run test:ci-phase819`.
|
||||
|
||||
@@ -86,6 +86,18 @@ function matchView (view, spec) {
|
||||
if (n > Number(expected)) return false
|
||||
continue
|
||||
}
|
||||
if (key === 'guildSyncWatermarkPresent') {
|
||||
if (!expected) return true
|
||||
const wm = view?.guildSyncHealth?.syncWatermark
|
||||
const ts = Number(wm?.sinceTimestamp) || 0
|
||||
if (ts <= 0 && !wm?.sinceMessageId) return false
|
||||
continue
|
||||
}
|
||||
if (key === 'guildSyncAckPeersMin') {
|
||||
const n = (view?.guildSyncHealth?.ackPeers || []).length
|
||||
if (n < Number(expected)) return false
|
||||
continue
|
||||
}
|
||||
if (key === 'activeChannelMessagesMin') {
|
||||
if ((view?.messages || []).length < Number(expected)) return false
|
||||
continue
|
||||
|
||||
+82
@@ -6754,6 +6754,88 @@ class HeadlessSession {
|
||||
}
|
||||
}
|
||||
|
||||
/** Phase 821: 3-peer mesh — ACK watermark fanout on host + both guests. */
|
||||
async runGuildMeshTripleAckWatermarkJourney () {
|
||||
const { connectGuildMeshTriple } = require('./mesh-helpers')
|
||||
const token = `ack821-${Date.now()}`
|
||||
const base = path.join(os.tmpdir(), `pearcord-agentctl-ack821-${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: 'ackhost821', displayName: 'Ack Host 821' })
|
||||
await host.createGuild({ name: 'Ack Watermark Triple 821', 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: 'ackguest821a', displayName: 'Ack Guest 821a' })
|
||||
await guest2.registerUser({ username: 'ackguest821b', displayName: 'Ack Guest 821b' })
|
||||
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)
|
||||
const chId = (await host.refreshView()).activeChannelId
|
||||
if (!chId) throw new Error('active channel missing')
|
||||
await guest1.ipc({ type: 'select-channel', channelId: chId })
|
||||
await guest2.ipc({ type: 'select-channel', channelId: chId })
|
||||
await guest1.wait({ activeChannelId: chId }, 30000)
|
||||
await guest2.wait({ activeChannelId: chId }, 30000)
|
||||
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)
|
||||
await host.sendGuildMessage(token)
|
||||
const msgWait = {
|
||||
activeChannelMessageIncludes: token,
|
||||
guildSyncWatermarkPresent: true
|
||||
}
|
||||
await host.wait(msgWait, 90000)
|
||||
const gid = host.platform.guild?.guild?.id
|
||||
for (const sess of [host, guest1, guest2]) {
|
||||
if (gid && typeof sess.platform.clearGuildSyncPushHalt === 'function') {
|
||||
sess.platform.clearGuildSyncPushHalt(gid)
|
||||
}
|
||||
if (typeof sess.platform._fanoutGuildSyncRequestWithAckWatermarks === 'function') {
|
||||
sess.platform._fanoutGuildSyncRequestWithAckWatermarks(chId)
|
||||
} else if (typeof sess.platform.requestGuildSyncFanout === 'function') {
|
||||
sess.platform.requestGuildSyncFanout()
|
||||
}
|
||||
}
|
||||
await guest1.wait(msgWait, 90000)
|
||||
await guest2.wait(msgWait, 90000)
|
||||
const hv = await host.refreshView()
|
||||
const g1v = await guest1.refreshView()
|
||||
const g2v = await guest2.refreshView()
|
||||
const hostFanout =
|
||||
typeof host.platform._fanoutGuildSyncRequestWithAckWatermarks === 'function'
|
||||
? host.platform._fanoutGuildSyncRequestWithAckWatermarks(chId)
|
||||
: null
|
||||
return {
|
||||
token,
|
||||
channelId: chId,
|
||||
hostFanoutPeers: hostFanout?.peerCount,
|
||||
hostWatermark: hv.guildSyncHealth?.syncWatermark,
|
||||
guest1Watermark: g1v.guildSyncHealth?.syncWatermark,
|
||||
guest2Watermark: g2v.guildSyncHealth?.syncWatermark,
|
||||
guest1AckPeers: (g1v.guildSyncHealth?.ackPeers || []).length,
|
||||
guest2AckPeers: (g2v.guildSyncHealth?.ackPeers || []).length
|
||||
}
|
||||
} finally {
|
||||
await host.close()
|
||||
await guest1.close()
|
||||
await guest2.close()
|
||||
}
|
||||
}
|
||||
|
||||
/** Phase 813: 3-peer mesh — both guests see full roster (host + 2 joiners). */
|
||||
async runGuildMeshTripleMemberRosterJourney () {
|
||||
const { connectGuildMeshTriple } = require('./mesh-helpers')
|
||||
|
||||
Reference in New Issue
Block a user