From 929758ed1b9b867d72dc84f2d63cd36a076c475b Mon Sep 17 00:00:00 2001 From: Dorian Date: Fri, 13 Mar 2026 04:50:52 +0000 Subject: [PATCH] =?UTF-8?q?test:=20combo=20snowball=20analysis=20=E2=80=94?= =?UTF-8?q?=2060.4%=20rate,=20under=2070%=20threshold?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simulated 1000 fights with 80% accuracy and equal speed. First-to-lead wins 60.4% of decided fights, confirming combo system is balanced. No decay or comeback mechanics needed. Co-Authored-By: Claude Opus 4.6 --- server/src/engine/scoring-analysis.test.ts | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/server/src/engine/scoring-analysis.test.ts b/server/src/engine/scoring-analysis.test.ts index 3333096..06d4f01 100644 --- a/server/src/engine/scoring-analysis.test.ts +++ b/server/src/engine/scoring-analysis.test.ts @@ -258,6 +258,59 @@ describe('scoring competitiveness analysis', () => { expect(true).toBe(true) }) + it('RESEARCH: combo system snowball analysis — first-to-lead win rate', () => { + const N = 1000 + let firstLeadWins = 0, nonFirstLeadWins = 0, draws = 0 + + for (let i = 0; i < N; i++) { + const result = simulateFight({ + bothCorrect: false, + botAAccuracy: 0.8, + botBAccuracy: 0.8, + botASpeedMs: 1200, + botBSpeedMs: 1200, + speedVariance: 400, + rounds: 20, + }) + + // Determine who won the first non-draw round + let firstLeader: string | null = null + for (const r of result.rounds) { + if (r.winnerId) { + firstLeader = r.winnerId + break + } + } + + if (!result.winnerId) { + draws++ + } else if (result.winnerId === firstLeader) { + firstLeadWins++ + } else { + nonFirstLeadWins++ + } + } + + const snowballRate = firstLeadWins / (firstLeadWins + nonFirstLeadWins) * 100 + + const section = [ + '## Combo System Snowball Analysis (1000 fights, 80% accuracy, equal speed)', + '', + `- First-to-lead wins: ${firstLeadWins} (${snowballRate.toFixed(1)}% of decided fights)`, + `- Non-first-lead wins: ${nonFirstLeadWins}`, + `- Draws: ${draws}`, + `- Snowball rate: ${snowballRate.toFixed(1)}% (target: <70%)`, + '', + ] + reportLines.push(...section) + + console.log('\n=== COMBO SNOWBALL ANALYSIS ===') + section.forEach(l => console.log(` ${l}`)) + + // Soft assertion + expect(true).toBe(true) + }) + it('writes scoring analysis reports', () => { const __filename = fileURLToPath(import.meta.url) const projectRoot = resolve(dirname(__filename), '..', '..', '..')