From 39b6a67a56ba259b196cdbe9611b6a5f7c8fbd98 Mon Sep 17 00:00:00 2001 From: Hunter M Date: Sat, 8 Aug 2026 13:08:30 -0700 Subject: [PATCH] Stabilize randomized bot tests --- src/server/BotController.ts | 7 +++++-- tests/engine/BotBrain.test.ts | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/server/BotController.ts b/src/server/BotController.ts index d85b8a4..6957a7a 100644 --- a/src/server/BotController.ts +++ b/src/server/BotController.ts @@ -312,11 +312,14 @@ export class BotController { const delay = BOT_EMOTE_DELAY_MIN + Math.random() * (BOT_EMOTE_DELAY_MAX - BOT_EMOTE_DELAY_MIN); const botId = bot.id; const botName = bot.name; - bot.lastEmoteTime = now; - this.pendingEmoteTimeout = setTimeout(() => { if (this.destroyed) return; this.pendingEmoteTimeout = null; + // Cooldown is defined between audible/visible emotes, not between the + // times they were scheduled. Random delivery delays can differ, so + // recording `now` above could let two emitted reactions land closer + // together than BOT_EMOTE_COOLDOWN_MS. + bot.lastEmoteTime = Date.now(); this.onBotEmote?.(botId, botName, reactionId); }, delay); diff --git a/tests/engine/BotBrain.test.ts b/tests/engine/BotBrain.test.ts index aa1b610..c9d553d 100644 --- a/tests/engine/BotBrain.test.ts +++ b/tests/engine/BotBrain.test.ts @@ -987,6 +987,7 @@ describe('BotBrain', () => { let aggChallenges = 0; let conChallenges = 0; const trials = 500; + const randomSpy = vi.spyOn(Math, 'random').mockImplementation(seededRandom(0xC0A9)); for (let i = 0; i < trials; i++) { const aggResult = decide(game, 'p2', BOT_PERSONALITIES.aggressive, { @@ -999,6 +1000,7 @@ describe('BotBrain', () => { }); if (conResult?.type === 'challenge') conChallenges++; } + randomSpy.mockRestore(); // Aggressive should challenge more than conservative expect(aggChallenges).toBeGreaterThan(conChallenges);