- Add Zod schema for webhook response parsing (orchestrator.ts)
- Add Zod schemas for POST /respond and /react request bodies
- Add safe integer validation for batch count param
- Prefer cf-connecting-ip over spoofable x-forwarded-for
- Add ID format validation on URL params
- Add rate limiting on /auth/login (30/min) and /update (10/min)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All magic numbers in scoring.ts now reference constants from
lib/constants.ts: damage multipliers, score thresholds, quality
parameters, narration margins, and rounding factors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fontSrc blocked fonts.gstatic.com and styleSrc blocked fonts.googleapis.com,
causing Honk font to fail in production. The chromatic aberration pseudo-elements
then appeared as doubled plain text instead of a styled 3D effect.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sqlite.prepare() calls ran at module import time, before
runMigrations() created the analytics table, causing a crash loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add periodic cleanup of fightReactions Map (clears when >100 entries).
Add RSS/heap logging every 10 fights in fight-loop for memory monitoring.
Set --max-old-space-size=256 in Docker CMD as safety net.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
readLimitedBody already enforces 10KB body limit. Answer truncation
(2000 chars) and trash_talk truncation (200 chars) now reference
named constants from lib/constants.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 526 new prompts across all 16 challenge types with heavy
Bitcoin/cypherpunk themes. Factual types include multiple-choice
options. Separate file for maintainability, merged at runtime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lightning Round (daily 8-bot at noon UTC) and The Halvening
(weekly 32-bot Saturday 20:00 UTC). Auto-fills with mock bots,
runs matches via background loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create, join, seed by Elo, generate bracket matches with byes,
advance rounds on fight completion, finish tournament on champion.
Wire into orchestrator fight finalization.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create server/src/lib/logger.ts with info/warn/error methods that add
[botfights:tag] timestamps. Replace bare console.log/warn/error calls
in index.ts, seed.ts, routes/fights.ts, engine/queue.ts, engine/mock.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- app.ts: type serveFile context parameter as Hono Context
- bets.ts: replace catch(err: any) with err: unknown + narrowing
- fight-loop.ts: type pickMatchup style as union literal, replace
as any casts with proper result type
- tts-worker.ts: import KokoroTTS type, use ProgressInfo inference
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Elo-bracket matchmaking: prefer ±200, widen by 100 every 15s of waiting.
Add pickRankedChallenge() that filters to creative/open-ended only, never
multiple choice. Show ranked queue status, wait estimate, and "HARDER
PROMPTS" notice on JoinBoutPage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create seasons engine with getCurrentSeason(), getSeasonLeaderboard(),
and resetSeasonElo(). 20 Bitcoin-themed season names. Add currentSeason
column to fights table, set on fight creation. Elo soft-reset formula:
finalElo * 0.6 + 1200 * 0.4.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NIP-01 kind:1 notes posted for KOs, perfects, upsets, and big Elo
swings. Includes bot names, Elo changes, arena, and replay link.
Configurable via BOTFIGHTS_NOSTR_RELAYS and BOTFIGHTS_NOSTR_NSEC env
vars. Silently skips if NSEC not set.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lock bets when fight goes live, settle all bets atomically when fight
ends. Winners get Cashu payout tokens, losers forfeit. Draws refund
all bets. Settlement results persisted to bets table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Creator omni-morph now generates actual sprite sheets for morphed archetypes
- 3 new Creator showboats: bullet time attack, ₿ throne summon, disco dance
- Music: subtle tempo shift (+10 BPM max), longer phrases (8/16/24 bars),
smoother crossfades, less chaotic hi-hat at high intensity
- Server: security headers, body size limit, production error masking,
CORS origin warning, graceful shutdown with drain
- Payments: atomic consume (eliminates SELECT/UPDATE race), release reverts DB
- Fight loop: round events for live TUI, retro displayPrompt
- Frontend: pass pubkey in payment/queue requests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TTS fixes:
- Remove 60-char truncation in FightViewer — let speakAnswer handle limits
- Smart truncation at sentence boundaries (period, comma, etc.) up to 200 chars
- Chrome keepalive: periodic pause/resume prevents silent 15s cutoff bug
- Deduplicated cleanup logic in speakAsync/speakAsyncWithRate
Retro mode:
- Simplified challenge prompt from verbose wall of text to clean 3-line format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every fight now includes one Retro Mode round where bots submit
gamepad combo inputs (↑↓←→ A B). 24 moves across 4 tiers: basic
(always shown), standard (partially revealed), super (must discover),
and ultra (KONAMI CODE for 50 dmg). Discovery bonus gives 1.5x damage.
Includes pixel-art gamepad overlays (P1/P2) with animated button
presses, retro-specific narrations, and mock bot combo responses
scaled by ELO.
Also adds loops/plan.md with 11-phase production hardening roadmap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move crypto key init from module-level throw to lazy getKey() — only
errors when encrypt/decrypt are actually called. Downgrade env var
check in index.ts from fatal exit to warning.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fight Card page: dramatic poster background with cross-hatch, spotlights,
vignettes, corner brackets, scan lines; 3D VS orb with punch animation;
selectable undercard with main event always pinned at top
- PosterSprite: high-quality 480px poster frame with 6-pass renderer
(aura, glow, bevel, specular, particles); PixelGlove component
- 12-char bot name limit across all forms and server validation
- Mock bots: all 100 now have diverse archetypes (25 types), 25% human
fighters; seedMockBots updates existing bots on restart
- Leaderboard: inline SpritePreview next to each bot name
- Nostr auth: persistent login, nsec copy button
- Wallet: NWC + Lightning Address, ranked fight flow
- Server: payments, ranked queue, customization endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ranked-queue.ts with 60s timeout, ELO matching, no-mock guard, and
automatic refund on timeout. Wire orchestrator to accept mode param,
track satsWagered in finalize transaction, trigger payWinner on ranked
win and refundEntry on ranked draw.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements createEntryInvoice, checkPaymentStatus, payWinner, refundEntry,
redeemCashuToken, and recoverOrphanedPayments. Uses nostr-tools for NWC
protocol (NIP-47) and @cashu/cashu-ts for ecash fallback payouts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete betting infrastructure:
- Bets schema (SQLite) with escrow status tracking
- Cashu token verification + minting (stub for real mint)
- Lightning invoice creation + withdrawal (stub for real LN node)
- Bet placement with odds lock, settlement on fight end
- Payout automation for winners, refunds on draws
- Bet history by pubkey + fight pool info
- Verifiable bet proofs for transparency
- API routes: /api/bets/{odds,place,fight,history,deposit,withdraw}
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Converts ELO ratings + streaks + recent form into betting odds.
Supports decimal, fractional, and American formats.
Includes bet validation, payout calculation, and 27 tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- answers.test.ts: 19 tests covering all 10 checkAnswer() tiers
- scoring.test.ts: 30 tests for scoreRound, calculateElo, calculateTier, applyModifiers
- challenges.test.ts: 16 tests for pickChallenge, type exclusion, data integrity
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- scoring.ts: wire arena damage modifiers (speed_2x, roast_2x, etc.) into applyModifiers()
- human-responses.ts: use challenge.timeout_ms instead of hardcoded 8s
- FightPage.vue: add route watcher for clean state reset on navigation
- Validated all 800 prompts: 0 duplicates, all factual have answers, all choices have 4 items
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove stray duplicate template block outside TEMPLATES array that caused parse error preventing server startup (fixes /api/queue/status 500)
- Add choices field to Challenge/PromptEntry interfaces for multiple choice support
- Allow voice lines to overlap naturally instead of cancelling previous speech on every call, with safety flush at depth > 3
- Buffer challenges during cooldown in polling path, auto-submit random choice on timeout
- Block auto-battle for human fights, guard replay-done auto-transition
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Server-side choice generation for all 22 challenge types (factual + creative)
- Mobile: 3 multiple-choice buttons replace keyboard input (4s timer)
- Two-row VS bar on mobile (names row + HP bars row) in FightPage and FightViewer
- Battle log hidden on mobile to maximize canvas visibility
- Arena page responsive: stacking header, tighter fight cards, no name overflow
- Profile page two-column desktop layout with contained sprite display
- Human fighter sprites with baby growth system
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add SSE human_challenge listener for instant input activation with auto-focus
- Buffer challenges during 3s round cooldown, apply with correct remaining time
- Map 'human' archetype to fighter-looking archetypes (boxer, ninja, etc.) in sprite system
- Show challenge questions in battle log via round_start SSE events
- Ensure human players are always botA (left side) in queue matchmaking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add choose-mode step: "I BUILD BOTS" vs "I FIGHT MYSELF" paths
- Human registration with baby avatar picker, no webhook required
- Live fight scene with SSE round streaming and real-time challenge UI
- 5-second timer per round, submit answers via browser
- Baby → toddler → kid → teen → adult → hero → super growth stages
- Huge sparkly baby eyes, diapers, pacifiers, bibs, rattles, rosy cheeks
- Speech bubble positioning fix (pushed to outside of sprite)
- Canvas text rendering via offscreen canvas to bypass kaplay color issues
- Voice timing improvements: await pauses between voice lines and hits
- 30 devastating announcement lines, 15 critical/hit word variants
- Orchestrator human player detection + waitForHumanResponse system
- Server endpoints: GET /challenge/:botId, POST /respond/:botId
- Human player auth: register-human route, isHuman flag on login
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Background fight loop: mock bots auto-fight every ~45s for site activity
- Quiet hours (2-8 UTC) run 4x slower, jitter prevents robotic timing
- Configurable via FIGHT_LOOP_ENABLED, FIGHT_LOOP_INTERVAL_MS
- Queue timeout: 30s in prod (was 3s), configurable via QUEUE_TIMEOUT_MS
- CORS: env-configurable via CORS_ORIGIN (default '*')
- Homepage: 40 cycling taglines with typewriter effect
- docker-compose: document all new env vars
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add .run() to all Drizzle queries inside sqlite.transaction() in
orchestrator.ts and mock.ts — queries were building but never executing,
leaving fights stuck as 'live' forever
- Remove spectator crowd from drawArenaDecor()
- Rename duplicate spawnProp to spawnWeaponProp (was crashing module load)
- Replace canvas element on re-init to avoid "KAPLAY already initialized"
- Add safeText() to strip brackets from k.text() calls (Kaplay treats
[ ] as style markup, crashes on unclosed tags)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fight loop CLI with TUI renderer (ink-style terminal UI)
- Rate limiting middleware for API routes
- Queue cooldowns wired into orchestrator after fights
- Webhook test utility for bot debugging
- API docs route
- Expanded FightScene choreographies and weapon props
- Fix Drizzle transaction execution in orchestrator
- Schema additions, scoring/challenge/mock expansions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add fight-loop CLI for automated mock fights with elo-based matchmaking
- Expand challenge types, scoring narrations, arenas, and mock bot pool
- FightPage "Fight again" buttons now only show for your own bot
- FightViewer async scene init, live fight polling with round counter
- Extract mock answers into separate answers module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>