Commit Graph
100 Commits
Author SHA1 Message Date
DorianandClaude Opus 4.6 2051a95e13 refactor: add centralized Zod validators for all API inputs
Create server/src/lib/validators.ts with reusable schemas for all API
inputs (auth, fights, bets, payments, tournaments, queue, docs).
Import and use in all route handlers, replacing inline validation.
Add formatZodError helper for user-friendly error messages.
77 test cases in validators.test.ts cover valid, invalid, boundary,
and attack inputs (SQL injection, XSS, prototype pollution).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:16:04 +00:00
DorianandClaude Opus 4.6 55d0f84251 chore: pin all dependency versions for reproducible builds
Remove ^ prefix from all 33 dependencies across root, server, and
frontend package.json files. Lockfile regenerated and verified with
pnpm install --frozen-lockfile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 06:21:16 +00:00
DorianandClaude Opus 4.6 e2dc2bbd70 feat: add eslint-plugin-security rules for static analysis
Adds 12 security-focused ESLint rules (unsafe-regex, eval, timing
attacks, child-process, bidi-characters, etc). One legitimate
non-literal RegExp in answers.ts suppressed with inline comment.
CI already runs pnpm lint + pnpm audit for SAST coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:26:10 +00:00
DorianandClaude Opus 4.6 abc081487c fix: pass archetype/customization to human morph sprite generation (BUG-10)
Human morph sprites were generated without archetype and customization
params, causing fallback to generic sprites instead of the bot's actual
appearance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:23:53 +00:00
DorianandClaude Opus 4.6 7698d560d6 fix: webhook verify shows loading spinner and better error on failure
Added isVerifyingWebhook state with spinner and disabled button during
webhook test. Improved error message to guide user on retry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:20:14 +00:00
DorianandClaude Opus 4.6 642da1e477 fix: polling backoff escalates on errors — 1.5s → 3s → 6s → 8s max
Changed from fixed 1.5s setInterval to recursive setTimeout with
exponential backoff on consecutive errors. Resets to 1.5s on success.
Added 2 tests verifying backoff escalation and reset behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:18:00 +00:00
DorianandClaude Opus 4.6 5bc8932d25 test: E2E specs for signup, fight replay, and leaderboard flows
Bot registration (3 tests), human registration (1 test), fight replay
(2 tests for JS error checking), and leaderboard (3 tests for rendering).
All use Playwright with text-based selectors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:15:46 +00:00
DorianandClaude Opus 4.6 a7520be0e7 test: add Playwright E2E infrastructure with smoke test
Set up Playwright with Chromium, dev server auto-start, test helpers
for seeding bots and programmatic auth. Added smoke spec that verifies
homepage and leaderboard load without crashes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:14:15 +00:00
DorianandClaude Opus 4.6 5e40221a2f test: SSE, polling, human, and concurrent fight integration tests
14 integration tests covering full fight lifecycle with real in-memory
DB: SSE event ordering, polling bot challenge/response flow, human
player response submission, and 3 concurrent fights without interference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:10:27 +00:00
DorianandClaude Opus 4.6 41c66d7732 test: full fight flow integration test with real in-memory DB
8 tests covering: complete fight lifecycle, HP progression, ELO
updates, concurrent fight prevention, round data validity, ELO
conservation, status transitions, and win streak tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 05:00:25 +00:00
DorianandClaude Opus 4.6 fc00490d61 test: speed meta analysis — 50ms gap wins 95.4% when both correct
Critical finding: when all bots answer correctly, even a 50ms speed
advantage wins 95.4% of fights. At 100ms+ gap it's 100% deterministic.
ELO separation reaches 450+ after just 50 fights. Speed completely
dominates the "all correct" meta.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:56:01 +00:00
DorianandClaude Opus 4.6 9c55850b70 test: tier balance analysis — system well-balanced across all tiers
Same-tier: ~50/50 win rates. Adjacent tiers: 70-93% higher-tier wins.
2-tier gap: 87-99% higher wins. K=32 ELO factor appropriate.
Legend vs Platinum: 99% win rate confirms clear skill separation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:54:37 +00:00
DorianandClaude Opus 4.6 929758ed1b test: combo snowball analysis — 60.4% rate, under 70% threshold
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 <noreply@anthropic.com>
2026-03-13 04:50:52 +00:00
DorianandClaude Opus 4.6 9ad8f1f1eb fix: both-wrong partial credit + tiebreaker
When both bots answer wrong, the one with higher checkAnswer confidence
(closer to correct) gets +1 point advantage. Rewards trying over
timing out. Equally wrong remains a pure draw.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:47:04 +00:00
DorianandClaude Opus 4.6 c6c792dd9e feat: add answer confidence differential as scoring factor
When both bots are correct, the one with higher checkAnswer confidence
(exact match 1.0 vs fuzzy match 0.8) gets up to +1.0 bonus points.
This rewards precise answers over approximate ones, adding another
competitive dimension beyond pure speed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:45:53 +00:00
DorianandClaude Opus 4.6 cb8a45cfb3 fix: lower critical hit threshold from 4 to 3
Both-correct fights could almost never produce critical hits because
max margin at typical speed differences was ~2.2, far below threshold
of 4. Lowering to 3 yields ~15% critical hit rate (target 10-20%),
making speed differences produce more exciting fight dynamics.

Research findings: simulated 1000 fights with both bots answering
correctly. Critical rate went from 0% to 15.3% with new threshold.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:44:29 +00:00
DorianandClaude Opus 4.6 0f8057f6e0 feat: add 10 sophisticated trap_card injection attempts
Multi-turn simulation, authority impersonation, encoding tricks
(Base64, ROT13), fake JSON system prompts, red team framing,
reward manipulation, inverted instruction logic. All difficulty: hard.
Zero audit failures after addition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:43:01 +00:00
DorianandClaude Opus 4.6 631ace3727 feat: add 15 genuinely hard prompts for trivial challenge types
- speed_blitz: genesis block nonce, embedded headline, first halving
  block height, first pizza transaction value, OP_RETURN payload size
- math_blitz: difficulty adjustment period, sum formula, cross product
  magnitude, log2 calculation, secp256k1 field size
- animal_kingdom: octopus hearts, hummingbird flight, shark bones,
  giraffe blood pressure, cow stomach count
All tagged difficulty: 'hard' for round 5+ difficulty filtering

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:41:47 +00:00
DorianandClaude Opus 4.6 6c6981bea8 test: difficulty distribution audit + roundToDifficulty tests
- Test roundToDifficulty: rounds 1-2 easy, 3-4 medium, 5+ hard
- Test pickChallenge difficulty filtering works with round numbers
- Audit prompt difficulty tags across all 16 challenge types
- 8 types lack hard prompts, 3 lack medium prompts
- 82.7% of prompts are untagged (no difficulty attribute)
- Report written to loop/difficulty-distribution.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:39:33 +00:00
DorianandClaude Opus 4.6 ab1fa6e302 test: scoring competitiveness analysis — speed, accuracy, duration
Simulated 1000+ fights with controlled conditions:
- Speed dominance: faster bot (1.0s) wins 100% vs slower (1.5s)
- Accuracy impact: 90% correct wins 84% vs 70% correct at equal speed
- Both-correct max margin: 4.30 at extreme speed diff, barely crosses
  critical hit threshold (4)
- Fight duration: avg 11.2 rounds equal speed, 7.4 when speed diff

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:38:31 +00:00
DorianandClaude Opus 4.6 4d6e50d988 fix: checkAnswer best-match + decimal preservation + prompt data fixes
- checkAnswer now returns highest score across all accepted answers
  instead of first match, fixing 95 false-low-confidence results
- Skip string containment for purely numeric strings to prevent
  false positives like "1000" matching inside "10000"
- Preserve decimal points in normalize() (42.0 no longer becomes 420)
- Use word-boundary regex for number matching in responses
- Fix 47 wrong choices scoring too high (comma-formatted numbers,
  verbose choices matching terse answers)
- Fix 17 prompts where no choice matched any accepted answer
- Challenge audit now reports zero failures across all 1472 prompts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:35:54 +00:00
DorianandClaude Opus 4.6 6314861513 test: challenge difficulty + ambiguous prompts audits
Run heuristic LLM difficulty classification on all 1472 prompts:
- 43.6% TRIVIAL, 27.9% MODERATE, 21.4% HARD, 7.1% TRICK
- Hypothesis "80%+ TRIVIAL" rejected — distribution more varied

Ambiguous prompts audit found 517 issues:
- 22 rejected alternatives (single-char answers fail with prefixes)
- 368 substring conflicts between accepted answers
- 127 first-match-not-best scoring issues

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 04:07:29 +00:00
DorianandClaude Opus 4.6 b8acc1c95b test: comprehensive challenge audit — 1472 prompts, 176 issues found
Audit covers all factual prompts through checkAnswer. Findings:
- 95 low-confidence correct answers (substring collision at 0.8)
- 64 false-positive wrong choices (normalization strips commas)
- 17 choices missing correct answer (paraphrasing mismatch)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:16:49 +00:00
DorianandClaude Opus 4.6 39b8504157 test: add checkAnswer edge case tests with findings (15 cases)
Documents: unicode accent stripping not supported, 3-char reverse
containment false positives, first-match-not-best-match ordering,
yes/true equivalence in boolean checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:12:49 +00:00
DorianandClaude Opus 4.6 8b72bef22e fix: query all 3 Nostr relays in parallel, pick latest profile (BUG-F8)
fetchNostrProfile now uses Promise.allSettled to query all relays
concurrently. Aggregates results with latest-created_at-wins strategy
instead of stopping at the first relay that responds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:10:11 +00:00
DorianandClaude Opus 4.6 c288b23c13 fix: persist autoRestoreRan on globalThis to survive Vite HMR (BUG-F7)
Module re-evaluation during HMR reset autoRestoreRan to false, causing
duplicate auth-restore API calls. Now persists flag on globalThis.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:09:20 +00:00
DorianandClaude Opus 4.6 1c296c6f1c test: add frontend composable tests and remaining test files
useNostr (9), useFightCache (5), useOnlineStatus (4) composable tests.
Added fake-indexeddb dev dependency for IDB tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:08:01 +00:00
DorianandClaude Opus 4.6 806163c6c5 test: add frontend composable tests — useNostr (9), useFightCache (5), useOnlineStatus (4)
Tests cover login state, logout, signer detection, key persistence, IndexedDB
caching/eviction, online/offline detection, and singleton pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:07:50 +00:00
DorianandClaude Opus 4.6 11a76cc249 fix: selective leaderboard cache invalidation instead of full clear (BUG-S10)
Only invalidates __alltime__ and current season cache keys on fight completion,
preserving historical season caches. Test verifies selective behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:03:16 +00:00
DorianandClaude Opus 4.6 c224776c90 test: add payments.test.ts (12 cases) and expand bets.test.ts (30 cases)
Covers wallet connection, invoice creation, payment confirmation, zap validation,
odds calculation, escrow settlement, bet validation, and display conversion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:01:17 +00:00
DorianandClaude Opus 4.6 2576221e24 fix: replace sort-based rate-limit eviction with Map insertion-order iteration (BUG-S9)
O(k) oldest-first eviction instead of O(n log n) sort. Added 10k benchmark test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:56:41 +00:00
DorianandClaude Opus 4.6 f18b04ba20 test: verify global error handler returns 500 without stack traces (BUG-S7)
Global app.onError handler already in app.ts catches all unhandled route
exceptions. Production mode returns "Internal server error" only.
Tests verify no stack traces or file paths leak in responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:51:12 +00:00
DorianandClaude Opus 4.6 14dbb29377 test: add timeout draw and perfect victory ELO tests to lifecycle suite
- Both bots timing out every round: verified draw with zero damage
- Perfect victory (10-0): verified correct ELO calculation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:49:34 +00:00
DorianandClaude Opus 4.6 e6c3894443 test: add orchestrator test suite — utility functions and SSRF protection (9 tests)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:48:12 +00:00
DorianandClaude Opus 4.6 a96e8922b6 feat: add JWT blacklist for logout with TTL cleanup
blacklistJwt() adds token to in-memory blacklist until its natural expiry.
verifyJwt() checks blacklist before signature verification.
Cleanup interval removes expired entries every 10 minutes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:45:57 +00:00
DorianandClaude Opus 4.6 ca9f5f36e6 test: add NIP-98 edge cases — replay, future clock drift, URL path mismatch
Documents finding: no replay protection in NIP-98 verification.
Token replay within 120s window succeeds (mitigated by JWT issuance being idempotent).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:44:56 +00:00
DorianandClaude Opus 4.6 34a83fb0fc test: add auth routes test suite with 13 cases
Tests check-name validation, login pubkey validation, register name/pubkey
validation, register-human validation, NIP-98 session (valid + expired).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:43:57 +00:00
DorianandClaude Opus 4.6 6144fa7910 test: add queue test suite with 8 cases (cooldown, join, leave, snapshot)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:42:11 +00:00
DorianandClaude Opus 4.6 21f9650585 test: add poll-responses, NIP-98, and bot-auth test suites
- poll-responses.test.ts: 10 tests covering lifecycle, timeout, duplicate rejection
- nip98.test.ts: 7 tests covering valid token, expiry, method, signature, tags
- bot-auth.test.ts: 5 tests covering header auth, query params, invalid credentials

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:40:24 +00:00
DorianandClaude Opus 4.6 a49cc124fe test: expand human-responses tests to 11 cases (isHumanPlayer, getPendingAnswers, numericDistractors)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:37:21 +00:00
DorianandClaude Opus 4.6 5f732d139c fix: remove duplicate JWT_SECRET production check (BUG-S5)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:34:20 +00:00
DorianandClaude Opus 4.6 2e2a6f18cb test: verify /poll endpoint rate limiting returns 429 (BUG-S3)
Tests the actual rateLimit middleware with production mode via dynamic import.
Covers: under-limit allows, over-limit returns 429, window reset, per-IP
isolation, and poll endpoint config (30 req/1s window).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:33:32 +00:00
DorianandClaude Opus 4.6 5e0bc1dc00 test: verify correct/incorrect feedback in respond endpoint (BUG-1)
Tests confirm checkAnswer integration: correct answer returns
correct: true, wrong answer returns correct: false.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:17:16 +00:00
DorianandClaude Opus 4.6 004413457d fix: use 'invoiced' status on NWC fallback instead of invalid 'pending'
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:15:49 +00:00
DorianandClaude Opus 4.6 e7d3cab85a feat: add ErrorBoundary component with onErrorCaptured (BUG-F5)
Catches runtime errors in child components, displays user-friendly
error message with reload button. Wired into App.vue wrapping
router-view. Tests verify error capture and button rendering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:15:28 +00:00
DorianandClaude Opus 4.6 74cb5cc728 fix: NWC payment timeout/error now rejects properly (BUG-F4)
- Timeout and WebSocket errors reject with proper Error objects
- Caller catches and falls through to poll-based confirmation
- Preimage undefined check prevents calling confirm with no preimage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:10:50 +00:00
DorianandClaude Opus 4.6 acecc79d04 test: verify HumanFightPage timer cleanup on unmount (BUG-F3)
feedbackTimer, timerHandle, and pollHandle are all cleared in
onUnmounted. Test confirms cleanup pattern works correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:07:47 +00:00
DorianandClaude Opus 4.6 b4900cb66f fix: replace all silent .catch(() => {}) with console.warn (BUG-F2)
13 silent catch handlers replaced with descriptive console.warn logging
across 6 frontend files. No silent error swallowing remains.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:06:22 +00:00
DorianandClaude Opus 4.6 e5ed856df9 fix: SSE reconnection with exponential backoff (BUG-F1)
SSE now always attempts reconnection when fight isn't finished,
regardless of isLive.value. Uses exponential backoff (1s, 2s, 4s,
max 8s). Moved sseRetries to outer scope to persist across reconnects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:02:10 +00:00
DorianandClaude Opus 4.6 370d8643b7 fix: add Zod enum validation for challenge types in webhook tester (BUG-S6)
Validates challenge type against the full CHALLENGE_TYPES enum before
processing. Invalid types now return 400 instead of silently falling
back to speed_blitz.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:56:26 +00:00
DorianandClaude Opus 4.6 b82c2755aa fix: throw if JWT_SECRET missing in production (BUG-S5)
Production now requires JWT_SECRET env var. Added comprehensive JWT
tests: creation, verification, expiry, tampered payload, tampered
signature, and malformed token rejection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:48:30 +00:00
DorianandClaude Opus 4.6 e4a7f47e0f fix: validate Cashu token format before placing bets (BUG-S4)
Added getDecodedToken validation that rejects malformed tokens with
400 before any DB lookups. Tests cover empty, non-base64, truncated,
and random base64 tokens.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:46:24 +00:00
DorianandClaude Opus 4.6 c6a54d63c4 fix: add rate limiting to /poll endpoint + fix test type errors (BUG-S3)
- Add rateLimit(1_000, 30) middleware to GET /poll endpoint
- Fix Challenge type errors in human-responses test files (missing baseDamage)
- Add rate-limit unit test verifying 429 after exceeding limit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:41:59 +00:00
DorianandClaude Opus 4.6 48847d879c test: add human-responses unit tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:36:32 +00:00
DorianandClaude Opus 4.6 e48a984d96 test: verify human challenge race condition fix ordering (BUG-S2)
waitForHumanResponse synchronously stores pending challenge before
returning, ensuring SSE emit happens after storage. Tests verify
ordering, choice consistency, promise resolution, and cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:36:04 +00:00
DorianandClaude Opus 4.6 8468c89352 test: verify tournaments .get() is sync + add route tests
better-sqlite3 driver is synchronous — .get() does NOT need await.
Added tests for unknown pubkey (404) and missing pubkey (400) on join.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:32:37 +00:00
DorianandClaude Opus 4.6 d9e32123fe test: add test infrastructure for frontend and server
- Frontend: vitest.config.ts with vue plugin + jsdom, dummy component test
- Server: in-memory SQLite test DB factory + Hono testClient helper + smoke test
- CI: add pnpm audit and server coverage threshold steps
- Root: vitest workspace config for multi-project test discovery

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 22:30:43 +00:00
DorianandClaude Opus 4.6 6f0eb92ebb fix: both-wrong draws + double TTS entrance fix
Scoring: both-wrong is now a DRAW — equal scores (3/3), no winner,
symmetric minimal damage. Garbage answers no longer beat reasonable
ones just by being faster. Both-wrong narrations reflect the draw.

Entrance: removed duplicate announceDeepIntro() call from FightViewer
(was already called inside playEntrance). Removed _resetPositions()
after entrance (entrance already places fighters at home positions,
the extra reset caused a visible snap/reset).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 20:09:11 +00:00
DorianandClaude Opus 4.6 017d0e3e4c fix: consolidate bot setup into single step with doc download + mode picker
Merged bot-setup and choose-connection into one actionable step.
Users now see mode picker, download button for the correct guide
(BOTFIGHTS-WEBHOOK.md or BOTFIGHTS-POLLING.md), and safety info
all on one screen instead of two filler steps with no actions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:02:45 +00:00
DorianandClaude Opus 4.6 af50580aca fix: generated identity uses extension signer instead of local key
buildNip98Token checked window.nostr before secretKeyHex, so
"Generate New Identity" would sign with the browser extension's key
after saving. Now explicit keys always take priority over extensions.

Also made setup flow mode-aware: webhook users get BOTFIGHTS-WEBHOOK.md,
polling users get BOTFIGHTS-POLLING.md with matching copy prompts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:49:22 +00:00
Dorian bc4a52bc12 fixes 2026-03-12 16:35:59 +00:00
Dorian 45216e5dfc second human fight fixes 2026-03-11 10:58:03 +00:00
Dorian ea72c097c4 human fight sequence fix 2026-03-11 10:34:08 +00:00
Dorian 29a0a48eb1 human fight sequence fix 2026-03-11 10:02:37 +00:00
Dorian 974566778e characters invisible on human vs bot fight entrance fix 2026-03-11 09:17:20 +00:00
Dorian bcbcd17fce challenges fix 2026-03-11 08:35:03 +00:00
Dorian bbe656929c another fix for human choices 2026-03-11 00:13:31 +00:00
Dorian 112bcde515 human fight non multiple choice fix 2026-03-10 23:26:36 +00:00
DorianandClaude Opus 4.6 68e292183a fix: polling bots play practice fights as human players in browser
Polling bots have no external script running during practice mode,
so the poll would time out giving empty answers. Now overrides the
webhook URL to human.local so the browser UI handles challenges.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:02:35 +00:00
DorianandClaude Opus 4.6 95ed80335a feat: polling API, HMAC webhook signing, session-only keys, prod audio fix
- Add polling API (GET/POST /api/fights/poll) so bots don't need public URLs
- Add HMAC-SHA256 webhook signing (X-Botfights-Signature header)
- Stop auto-persisting nsec keys — session-only by default with opt-in "Remember on this device"
- Fix production TTS: add wav/mp3/ogg MIME types, /audio/* route, SPA blocklist
- Overhaul docs: mode selector (poll vs webhook), AI-first bot examples, security tab
- Fix duplicate sign-in buttons, login flow bugs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:34:22 +00:00
DorianandClaude Opus 4.6 150ce7447d fix: human vs AI fight bugs — CSP for TTS, invisible sprites, fight end sequence
- Allow huggingface.co in CSP connect-src (fixes Kokoro TTS model download)
- Add registerSW.js route (fixes PWA service worker 404)
- Add _resetPositions() safety after entrance (fixes invisible fighters)
- Fight end sequence works without canvas scene (KO/overlays/log always play)
- Pre-fight instructions in battle log for human players
- NIP-55 visibility sync and cleanup handlers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:00:20 +00:00
DorianandClaude Opus 4.6 63cc00fcb6 feat: add NIP-55 Android signer support for Amber/Primal login
When window.nostr isn't available (common on mobile Chrome where
extensions can't inject), fall back to NIP-55 nostrsigner: intent
URIs. This opens Amber/Primal directly to sign a NIP-98 event,
then redirects back with the signed event for JWT authentication.

- Build nostrsigner: URI with unsigned NIP-98 event + callback URL
- Process NIP-55 callback on page mount (extract signed event from URL)
- Auto-detect Android to show "SIGN IN WITH AMBER / PRIMAL" label
- Reduced window.nostr polling from 3s to 2s before NIP-55 fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:15:16 +00:00
DorianandClaude Opus 4.6 df70f5f093 fix: move BETA badge after green dot in navbar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:36:24 +00:00
DorianandClaude Opus 4.6 226d242552 feat: add BETA badge to header logo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:33:44 +00:00
DorianandClaude Opus 4.6 6dc50f5d5d feat: move creator pubkey to env, fix mobile TTS + signer, button loaders
Security:
- Move CREATOR_PUBKEY from hardcoded constant to BOTFIGHTS_CREATOR_PUBKEYS
  env var. Shared isCreatorPubkey() in constants.ts used by auth, admin,
  tournaments. Frontend checks authorization via API, not client-side.

Mobile fixes:
- Nostr signer: poll for window.nostr up to 3s (Amber injects late).
- TTS: auto-unlock AudioContext on first user interaction via
  installAutoUnlock() on fight page mount.

UX:
- Add loading spinners to "I BUILD BOTS" and "I FIGHT MYSELF" buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:31:58 +00:00
DorianandClaude Opus 4.6 dd3cbdae7f fix: mobile nostr signer detection, mobile TTS auto-unlock, button loaders
- Nostr signer: poll for window.nostr up to 3s on mobile (Amber injects
  late). Both login() and handleSignerLogin() now wait before failing.
- Mobile TTS: install global one-time click/touch/keydown handler to
  auto-unlock AudioContext when fight pages mount. Previously only
  triggered by explicit sound toggle, so mobile TTS silently failed.
- Add loading spinners to "I BUILD BOTS" and "I FIGHT MYSELF" buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:44:38 +00:00
DorianandClaude Opus 4.6 4897335686 chore: add PromptDifficulty type and nostr login planning doc
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:26:43 +00:00
DorianandClaude Opus 4.6 a98d94d24c feat: 56k modem SFX for code answers, fix crossed entrance voices
- Add sfxModem() — synthesized 56k handshake sound with carrier tones,
  data burst, and chirps. Plays instead of TTS for code_golf/hack_battle
  rounds and code-detected answers.
- Fix entrance voice overlap: remove duplicate announceDeepIntro() from
  robe entrance, add cancelPrevious to entrance-specific voice calls
  (girlfriend, bouncer, shopping cart, spotlight, creator) so they
  cleanly replace the global intro instead of overlapping.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:21:58 +00:00
DorianandClaude Opus 4.6 53ae4b485d feat: massively improve mock bot answer quality for hilarious seeded fights
- Expand all 5 creative answer pools from 5-10 to 25-30 entries each
- Fix factual wrong answers to pick from challenge's own wrong choices
  instead of random non-sequiturs like "banana" and "purple?"
- Reduce bad answer rate: 25% → 2.5% at elo 1200, 0% at elo 1300+
- Improve BAD_ANSWERS and WRONG_FACTUAL to be funny when they do appear
- 90%+ of all mock answers are now good attempts that make sense

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:11:49 +00:00
DorianandClaude Opus 4.6 3a5f473d25 fix: show full text in battle log and speech bubbles
Remove .slice(0, 120) truncation from battle log entries and
.slice(0, 60) from speech bubble calls. Increase bubble limits
to 200 chars, 24 chars/line, 8 lines so responses display fully.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 14:11:02 +00:00
DorianandClaude Opus 4.6 761c01f92f fix: reduce fighter sprite scale on mobile canvas
On narrow viewports (<600px), fighters were oversized due to the
desktop scale formula. Use reduced base (1.1) and tier (0.2) scale
factors on mobile while keeping desktop unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:56:50 +00:00
DorianandClaude Opus 4.6 a2416bbe19 fix: human fight timing, creative timer, TTS reliability, add sweary/vibe narrations
- Fix invisible characters in human mode: init live scene BEFORE starting
  challenge polling so entrance plays before first question appears
- Cap creative writing timer to 10s for multiple choice (just tapping buttons)
- Fix TTS reliability: precache priority phrases (Round 1-7, Fight!, K.O.)
  all at once instead of in slow batches; prevent duplicate precache runs
- Add 10 vibe-coded narrations (~20% chance): "I was vibe coded into existence"
- Add 15 sweary narrations (~30% chance): raw unhinged fight commentary
- Add sweary draw and retro narrations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 13:50:24 +00:00
DorianandClaude Opus 4.6 3ba05a66b4 feat: NIP-98 + JWT authentication with signer support
Replace insecure raw-pubkey auth with cryptographic NIP-98 signed
requests and server-issued JWT sessions. Logout now fully clears
all state including nsec. Add yellow "Use Nostr Signer" button
for Amber/NIP-07 remote signers.

- Server: JWT middleware (HMAC-SHA256, 24h expiry), NIP-98 verification
- Server: POST /api/auth/nostr/session endpoint
- Frontend: NIP-98 token builder + authFetch wrapper with JWT Bearer
- Frontend: All authenticated API calls use authFetch
- Security: logout clears JWT, pubkey, bot, nsec, and profile pic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:31:25 +00:00
DorianandClaude Opus 4.6 ad96d1158f feat: practice button on profile, fix rate limiter, fix mobile sprite rendering
- Add Practice button to BotProfilePage for quick sparring
- Fix rate limiter bug: all rateLimit() instances shared one counter map,
  causing global and per-route limits to corrupt each other. Each limiter
  now gets its own isolated map.
- Replace 8-digit hex colors (#ffd70066) with rgba() in sprite rendering
  for mobile browser compatibility (iOS Safari renders them as black boxes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:14:07 +00:00
DorianandClaude Opus 4.6 d0f0a84a57 feat: add first-time warning dialog for Fight For Sats
Shows a one-time warning when users first click "Fight For Sats" letting
them know it's vibe coded and to only use small sats amounts. Acknowledged
state persists in localStorage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:05:56 +00:00
DorianandClaude Opus 4.6 e6b5aa4b9b fix: mobile menu overlay, speech bubble timing, TTS static file fallback
- Mobile nav menu now overlays content (absolute positioning) instead of
  pushing it down
- Speech bubbles stay visible for minimum 400ms even when TTS resolves
  instantly or fails
- kokoroPlayCached checks audio cache and loads static files even when
  Kokoro worker hasn't loaded — fixes TTS not playing on production
- CORS_ORIGIN env now supports comma-separated origins
- Rename "VIDEO REPLAY" to play icon + "REPLAY"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:59:18 +00:00
DorianandClaude Opus 4.6 1a7ad74859 fix: prevent FightViewer random resets from concurrent kaplay init
- Guard initScene() with initializingScene flag to prevent concurrent calls
- Don't auto-reinit scene on WebGL context restore during active replay
- Block initScene() after component is destroyed
- Static audio files now play even before Kokoro worker loads
- kokoroSpeak/kokoroSpeakAsync check cache before requiring worker ready

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:58:13 +00:00
DorianandClaude Opus 4.6 52769ab43a feat: ship pre-generated TTS audio files for instant playback
71 static voice files (9.6MB) for round calls, intros, hype lines,
and challenge announces. These play instantly from file instead of
running Kokoro TTS generation in the browser. Dynamic content
(questions, answers, narrations) still uses Kokoro.

Includes Node.js generation script (scripts/generate-voice-files.mjs)
and modified tts.ts to check static file cache before worker generation.
Static audio works even before Kokoro model finishes loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:38:44 +00:00
DorianandClaude Opus 4.6 4c17379ad4 fix: harden TTS with 2s await timeout and 4s worker timeout for reliable fallback
Reduces worker generation timeout from 10s to 4s and adds 2s race on
awaitReady so slow Kokoro generation falls back to Web Speech API
quickly instead of stalling the fight.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:18:03 +00:00
DorianandClaude Opus 4.6 cb8a1d50fe feat: sync TTS voice with chat bubbles and battle log for zero-gap playback
Adds await-then-play pattern: audio is pre-generated and cached before
visuals appear, so log text + speech bubble + mouth animation + voice
all fire in the same frame. Prefetches both answers during question
playback for instant transitions. Adds hideSpeechBubble() to dismiss
bubbles when voice ends instead of fixed 5s timer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:15:54 +00:00
DorianandClaude Opus 4.6 e7d1f9b97b fix: update WTF modal description text and increase title/subtitle margins
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:51:53 +00:00
Dorian 67b5b4ff51 Merge branch 'overnight/2026-03-09' 2026-03-09 09:46:52 +00:00
DorianandClaude Opus 4.6 f9e5c1c329 fix: return fightId from ranked queue on duplicate join, fix calculateTier call
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:29:55 +00:00
DorianandClaude Opus 4.6 e31d49898b feat: show rejoin link when bot is already in a fight
- Track active fight IDs per bot in orchestrator (Set → Map)
- Return fightId in "already in fight" error responses (409)
- Frontend shows "REJOIN FIGHT" link instead of generic error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:27:48 +00:00
DorianandClaude Opus 4.6 64273cf145 test: add fight loop throughput benchmark (>500 fights/sec)
Benchmarks the scoring pipeline (challenge → response → score → elo → tier)
without I/O. Currently achieves ~8500 fights/sec.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:25:29 +00:00
DorianandClaude Opus 4.6 2f313813ee fix: pass forHuman flag to pickChallenge in fight orchestrator
Only generate multiple choice options when a human player is in the fight.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:21:45 +00:00
DorianandClaude Opus 4.6 98e6baccc1 fix: handle canvas context loss with recovery and fallback overlay
Listen for webglcontextlost/restored events on the fight canvas.
Show "recovering" overlay on context loss, re-init scene on restore.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:18:33 +00:00
DorianandClaude Opus 4.6 bcb323e30f fix: move dependency overrides to pnpm-workspace.yaml
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:15:40 +00:00
DorianandClaude Opus 4.6 d459097a7d feat: add WTF explainer modal on home page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:15:37 +00:00
DorianandClaude Opus 4.6 62b957e886 feat: seed fight card with scheduled fights in dev mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:15:33 +00:00