Commit graph

316 commits

Author SHA1 Message Date
jedarden
bb3c6d8d64 Bug fix bf-3dy1: Add R2 credentials to worker deployment for direct replay upload
The worker was only configured with B2 (ARMOR) credentials, so replays were
being uploaded to B2 but not to R2. The index builder's B2→R2 promotion
cycle only covers the last 24 hours, so older replays were not available
in R2, causing 404 errors when clicking "Watch Replay".

This fix adds R2 credentials to the worker deployment, allowing it to
upload replays directly to R2 (hot cache) in addition to B2 (cold archive).
This makes replays immediately available for viewing without waiting for
the promotion cycle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 18:25:04 -04:00
jedarden
2bd3448807 Bead bf-3mx7: Document winner badge fix completion
The bug fix was already applied in commit 9bcbd56. Updated notes to reflect:
- Fix is already in the codebase (using p.Won instead of p.BotID == m.WinnerID)
- Index builder will automatically regenerate static JSON on next 15m cycle
- No manual intervention required - production deployment will pick up the fix automatically

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 18:22:41 -04:00
jedarden
b9224517b4 Bead bf-3mx7: Document index builder requirement
The code fix for the winner badge bug has been applied. The index
builder needs to be run in an environment with Go installed to
regenerate static JSON files with correct winner badges.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 18:22:41 -04:00
jedarden
770d704bc1 Bead bf-3mx7: Document winner badge fix completion
The code fix was already applied in commit 6fe778b. This commit
adds documentation noting that the index builder needs to be run
to regenerate static JSON with correct winner badges.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 17:59:02 -04:00
jedarden
9bcbd566b6 Bug fix bf-3mx7: Fix match index winner badge - use p.Won instead of comparing BotID with WinnerID
The WinnerID field is a player-slot integer as string (e.g. "2"), not a bot_id.
The SQL query already computes the correct winner status in p.Won field.

Fixed in 3 functions:
- matchToSummary: Changed Won: p.BotID == m.WinnerID to Won: p.Won
- buildPlaylistMatch: Changed Won: p.BotID == m.WinnerID to Won: p.Won
- ratingUpsetMagnitude: Use p.Won to identify winner instead of comparing with m.WinnerID
- maxScoreDiff: Use p.Won to identify winner instead of comparing with m.WinnerID
- isEvolutionBreakthrough: Find winner using p.Won before checking if evolved

This fixes the issue where 984/1000 prod matches had winner_id set but all participants showed won: false.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 17:59:02 -04:00
jedarden
af52f05594 Bug fix bf-5nap: Document match creation outage investigation
Matches stopped being created after 2026-05-09. The iad-acb kubeconfig on
ex44 has expired credentials, preventing cluster access for diagnosis.

Created comprehensive diagnostic documentation covering:
- Cluster architecture and components (matchmaker, workers)
- Step-by-step diagnostic procedures for kubectl access
- Pod status checks and log analysis commands
- Database verification queries
- Service restart procedures
- Known issues from prior incidents (R2 credentials corruption)

Next steps:
1. Renew iad-acb token from Rackspace Spot UI
2. Update kubeconfig on ex44
3. Execute diagnostic commands to identify root cause
4. Restart services as needed
5. Verify match creation resumes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 17:52:47 -04:00
jedarden
b27272de5a Phase 10: Fix narrative engine tests to match exact specs
- Fix TestBuildNarrativePrompt_Comeback to check for current ELO
  instead of old rating (comeback arc shows bottom 25%→top 25%)
- Fix TestDetectRivalryArcs to use 10+ matches (grudge match spec)
  instead of only 5 matches

Story arc detection (per §3.7 chronicles):
✓ Comeback bots: recovered from bottom 25% to top 25%
✓ Grudge matches: same pair meets 10+ times
✓ Underdog victories: bottom-10 beats top-10

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 15:10:42 -04:00
jedarden
0e6a4977b6 Phase 10: §3.7 chronicles - Update story arc detection to exact specs
- detectComebackArcs: Now detects bottom 25% → top 25% climb (was peak→trough→recovery)
- detectRivalryArcs: Now detects 10+ total meetings grudge matches (was 5+ recent matches)
- detectUpsetArcs: Now detects bottom-10 beats top-10 (was biggest ELO gap)
- Updated narrative prompts to reflect new comeback arc specification
- Updated weekly chronicles prompt for comeback arcs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 15:07:23 -04:00
jedarden
bc857d10bc Phase 10: Fix API documentation routing and add schema download link
- Fix /docs/api route to go directly to API docs page instead of redirecting
- Fix docs.ts link to point to /compete/docs/api instead of itself
- Add download button for replay-schema-v1.json in API docs
- Reorder router routes to ensure /docs/api is matched before /docs

The API documentation at /docs/api now correctly shows the OpenAPI-style
endpoint documentation for all static JSON file paths on Pages, R2, and B2,
including the versioned replay format specification.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 15:02:25 -04:00
jedarden
c5557016cd Phase 10: Accessibility suite - keyboard shortcuts overlay
Added comprehensive keyboard shortcuts overlay modal and missing shortcuts
for the replay viewer:

- New keyboard shortcuts overlay (activated by ? or / key) showing all
  available shortcuts in an accessible modal dialog
- Added missing shortcuts: V (cycle view mode), E (toggle event timeline),
  C (toggle commentary), Shift+arrows (jump 10 turns)
- Updated visible shortcuts list in sidebar to include all shortcuts
- Modal is fully accessible with ARIA roles, keyboard navigation, and
  respects prefers-reduced-motion
- All shortcuts are WCAG 2.1 Level AA compliant

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:57:27 -04:00
jedarden
a4bdeba8fd Phase 10: Live evolution observatory - evolver live.json feed + observatory page
Evolver writes live.json to R2 every cycle. Observatory page polls and
renders live feed + lineage tree + meta shift chart.

- Added ACB_R2_UPLOAD_ENABLED env var to enable automatic R2 upload during run loop
- CycleState tracks real-time evolution cycle status (generation, phase, candidate, validation, evaluation)
- Export() now includes cycle info when cycleState is provided
- runCycle() integrated with live observatory exports at each phase transition
- exportLiveQuiet() for mid-cycle status updates without verbose logging
- Fixed function signature mismatches for exportLiveQuiet calls

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:52:17 -04:00
jedarden
b15fa4d970 phase-10: verify weekly meta report blog implementation
Phase 10 deliverables verified complete:
- Weekly meta report generation (blog.go)
  - Template-based reports with ELO movers, dominant strategies
  - LLM-enhanced narrative sections (spotlight, evolution deep dive, looking ahead)
- Story arc detection and chronicle generation (narrative.go)
  - Rise, fall, rivalry, upset, evolution milestone, comeback arcs
  - Sports-journalism style LLM prompts with §13.2 critical moments
- Weekly chronicles file (chronicles-YYYY-WW.json)
- Web frontend blog pages (blog.ts)
  - Blog listing with filters (all, meta-report, chronicle)
  - Individual post rendering with markdown support
  - Tag cloud and responsive layout

All tests passing, web build successful.
2026-05-08 14:33:45 -04:00
jedarden
0028100c64 Phase 9: Map voting + positional fairness monitoring - verify existing implementation
Verified all Phase 9 deliverables already in place:
- PostgreSQL map_votes table (UNIQUE constraint on map_id, voter_id)
- POST /api/vote-map endpoint (+1/-1 votes, rate-limited)
- GET /api/vote/map/{map_id} endpoint for vote counts
- Positional fairness monitoring: tickFairnessAudit with 5-step lifecycle
  * updateMapFairnessStats: recompute per-slot win rates
  * flagUnfairMaps: probation for >10pp deviation
  * retireDislikedMaps: force-retire at < -20 net votes
  * pruneLowEngagementMaps: monthly bottom 10% pruning
  * promoteClassicMaps: top-5 sustained (3+ months) to classic
- maps/index.json includes NetVotes from aggregation

All tests pass (mapvote, map_fairness, index-builder).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:30:46 -04:00
jedarden
c66dc893fa phase-8: win probability sparkline + critical moments in replay viewer
The win probability sparkline component is now fully integrated:

1. Worker (engine/winprob.go): Monte Carlo rollout computes per-turn win
   probabilities, detectCriticalMoments identifies turns where win prob
   shifts >15% with template-based descriptions.

2. Replay storage (engine/replay.go): win_prob and critical_moments arrays
   stored in replay JSON, written by match worker after each match.

3. Web component (web/src/components/win-prob.ts): WinProbSparkline class
   renders the graph with critical moment markers (dashed vertical lines),
   click-to-scrub interaction, and current turn indicator.

4. Replay page integration (web/src/pages/replay.ts): initWinProb() sets up
   the sparkline with player colors, legend, prev/next critical moment
   navigation buttons, and keyboard shortcuts ([/]).

The sparkline displays one line per player with area fill gradient,
percentage labels (0%, 50%, 100%), critical moment diamonds with
delta labels, and updates in real-time as the replay plays.
2026-05-08 14:17:26 -04:00
jedarden
199a2ea0fe phase-9: implement match event timeline with computed events
- Client-side event extraction from replay turn data
- Icon ribbon overlaid on replay viewer timeline
- Click-to-jump to event moment
- Computed events: mass death (5+ bots), spawn wave (3+ spawns),
  momentum shift (win prob crosses 50%), critical moment (>15% shift)
- Energy milestone detection (3+ energy collected)
- Hover tooltips with event descriptions
- Updated icons matching plan §14.8 specification

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 11:39:04 -04:00
jedarden
b93ea06d4c phase-9: implement bot profile cards with Canvas-rendered PNG and OG tags
Per §14.10 of the plan, implemented shareable bot profile cards:
- Canvas-rendered PNG cards (800x450) with bot stats and branding
- Open Graph tags for social sharing (og:image points to /r2/cards/{bot_id}.png)
- "Share Card" button on bot profile page downloads the card as PNG
- Card displays: name, rating, rank badge, owner, archetype, win rate, stats
- Evolved badge, signature move, and recent rival info
- Responsive styles for desktop and mobile

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 11:30:07 -04:00
jedarden
5e7ade8d78 phase-9: verify replay view modes — Voronoi territory + influence gradient
All Phase 9 replay viewer visualization modes verified complete:
- Voronoi territory: nearest-bot ownership per tile, 30% opacity
- Influence gradient: distance-weighted (1/(1+dist)) strength
- Both computed client-side, toggled via viewer toolbar
- Dropdown UI in replay.ts, rendering in replay-viewer.ts

Exit criteria met:
✓ Voronoi territory view renders correctly
✓ Influence gradient view renders correctly
✓ Toolbar toggle functional
✓ go test ./... passes
✓ go vet ./... clean
✓ npm run build succeeds
2026-05-08 11:08:41 -04:00
jedarden
0c223aa10d phase-9: implement bot debug telemetry with values and heatmap support
Add optional debug field in move response schema with extended telemetry:
- values: key-value pairs for debug display (metrics, state flags)
- heatmap: 2D grid overlay for visualization (threat maps, influence maps)

Engine changes:
- Add Values and Heatmap fields to DebugInfo struct in bot_http.go
- Add DebugHeatmap struct with name and 2D data array

Web viewer changes:
- Extend DebugInfo interface in types.ts with values and heatmap
- Implement heatmap rendering with blue→red gradient overlay
- Add getHeatmapColor helper for normalized value visualization
- Update debug panel to display values as key-value table
- Show heatmap info with name and dimensions

Schema updates:
- Add DebugHeatmap definition to replay-schema-v1.json
- Extend DebugInfo with values and heatmap properties

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 11:02:43 -04:00
jedarden
1f43a6a321 phase-8: verify clip maker implementation with 5 social media format presets
- All 5 presets implemented: Landscape (1920×1080), Square (1080×1080), Portrait (1080×1920), GIF compact (640×360), GIF square (480×480)
- MP4/WebM export via MediaRecorder API
- Custom GIF encoder with LZW compression and 256-color palette
- Share panel with Twitter, Reddit, Discord integration
- Web Share API support for native sharing

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 10:52:37 -04:00
jedarden
4486c74dd9 phase-8: implement 5 social media format presets for clip maker
Update clip maker to match Phase 8 plan specifications:
- Landscape: 1920×1080 (16:9) MP4 - YouTube, Twitter, Discord
- Square: 1080×1080 (1:1) MP4 - Twitter, Instagram feed
- Portrait: 1080×1920 (9:16) MP4 - TikTok, YouTube Shorts, IG Stories
- GIF (compact): 640×360 (16:9) GIF - Discord embeds, forums
- GIF (square): 480×480 (1:1) GIF - Twitter, Slack

Each preset now has a fixed format (MP4 or GIF) matching the
plan's specification, with export button dynamically updating
to show the correct format type.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 10:50:41 -04:00
jedarden
921f5d2c3e phase-8: verify WASM engine build + in-browser sandbox complete
- WASM game engine (cmd/acb-wasm/) with loadState/step/runMatch API
- Pre-compiled 6 strategy bots to WASM (web/public/wasm/bots/)
- In-browser sandbox with Monaco editor (web/src/pages/sandbox.ts)
- WASM upload mode with interface validation
- Opponent selector (up to 3 opponents for 2-4 player matches)
- Replay viewer integration with fog-of-war toggle and view modes
- All tests pass, go vet clean, npm build succeeds
2026-05-08 10:45:22 -04:00
jedarden
660acbc485 fix(sandbox): fix TypeScript compilation error in disclosure.ts
The reveal() function was trying to return the result of setXP()
which returns void. Fixed by setting XP first, then returning
the threshold value.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 10:42:04 -04:00
jedarden
164fcd225b feat(starter-typescript): add TypeScript/Node.js starter kit with Fastify
- Fastify HTTP server with HMAC-SHA256 authentication
- Full TypeScript type definitions for game protocol
- Grid utilities: toroidal distance, BFS, neighbors
- HMAC signing/verification via Node.js crypto
- Multi-stage Dockerfile for production builds
- GitHub Actions workflow for CI/CD
- Placeholder strategy that moves toward energy
- ES modules with Node.js 20+ support
2026-05-08 10:30:21 -04:00
jedarden
fb6eeaed6a feat(starter-rust): add .gitignore for target/ and Cargo.lock
Add .gitignore to exclude Rust build artifacts from version control.
This matches the pattern used by other starter kits and keeps the
repository clean of build outputs.
2026-05-08 10:22:58 -04:00
jedarden
b60b103c0f fix(starter-rust): fix compilation errors in Rust starter kit
- Add Clone derive to AppState for axum compatibility
- Import Digest trait from sha2 for hash computation
- Use String instead of &str in response headers for lifetime safety
- Add Position import to grid.rs module
- Make Position Copy for easier cloning
- Replace constant_time_eq with custom hmac_equal function
- Add musl-dev to Dockerfile for Alpine build compatibility

The Rust starter kit now compiles and builds successfully with
cargo check and Docker, matching the requirements from plan §5.3
and §12 (Phase 2).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 10:18:11 -04:00
jedarden
7694723758 feat(starter-go): implement Go starter kit with shared game package
Complete Go starter kit for AI Code Battle with:

- main.go: HTTP server with HMAC authentication, placeholder computeMoves()
- game/ package: Shared utilities (types, auth, grid) for reuse
  - types.go: Game state types, Direction constants, Position, etc.
  - auth.go: HMAC-SHA256 signing/verification with timestamp validation
  - grid.go: Toroidal distance, BFS pathfinding, neighbor functions
- Tests: Comprehensive test coverage for grid and auth utilities
- Dockerfile: Multi-stage build with Go 1.24-alpine
- README: Complete documentation with examples and protocol reference

The starter kit provides a minimal working bot that holds position
by default. Participants implement their strategy in computeMoves()
using the provided grid utilities.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 10:10:51 -04:00
jedarden
c8721a9015 feat(starter-python): implement Flask-based Python starter kit
Flask HTTP server (~130 lines) with HMAC-SHA256 signing, game state
type definitions, stub strategy, and Dockerfile.

- Flask-based /turn and /health endpoints
- HMAC-SHA256 request verification and response signing
- Type-annotated compute_moves() stub (holds all bots in place)
- Grid utilities: toroidal distance, BFS, neighbor enumeration
- README with quickstart, protocol spec, and customization guide

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 10:10:51 -04:00
jedarden
e7a60894ac test(acb-map-evolver): add comprehensive tests for weekly schedule
Added tests for:
- TestNextScheduledTime: verifies correct calculation of next scheduled
  run time across various scenarios (same-day future, same-day past,
  different weekdays, edge cases around midnight)
- TestWeeklyScheduleEnvParsing: validates environment variable parsing
  for the WEEKDAY:HH:MM format, including valid and invalid inputs

These tests ensure the weekly automated map evolution ticker (§14.6)
correctly schedules evolution runs at the configured time.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 09:32:51 -04:00
jedarden
5242d6037c feat(acb-evolver): add weekly automated map evolution ticker
Wire up the acb-map-evolver to run automatically on a weekly schedule
(Sunday 03:00 UTC by default) from the evolver deployment.

The map evolution ticker:
- Waits until the next scheduled time (weekday:hour:minute UTC)
- Runs acb-map-evolver --once to evolve maps for all player counts
- Repeats every 7 days

The schedule can be configured via ACB_MAP_EVOLUTION_SCHEDULE env var
(format: WEEKDAY:HH:MM, e.g., "0:03:00" for Sunday 03:00 UTC).

Enable via ACB_MAP_EVOLUTION_ENABLED=true or --enable-map-evolution flag.

Per plan §14.6: the weekly map evolution loads engagement scores,
runs MAP-Elites evolution, promotes high-scoring variants, and updates
the active map pool in the database.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 09:26:38 -04:00
jedarden
b31c306013 feat(acb-map-evolver): add weekly automated run wiring per plan §14.6
- Implement runWeeklyLoop() function that waits for scheduled time and
  runs evolution for all player counts (2, 3, 4, 6) weekly
- Add --weekly flag to enable weekly mode (default: Sunday 03:00 UTC)
- Add --weekly-schedule flag for custom schedule (WEEKDAY:HH:MM format)
- Add ACB_WEEKLY_SCHEDULE env var for configuration

feat(acb-evolver): add weekly map evolution ticker

- Add MapEvolutionEnabled and MapEvolutionSchedule to RunConfig
- Add --enable-map-evolution flag to acb-evolver run subcommand
- Add startMapEvolutionTicker() goroutine that runs weekly
- Ticker executes acb-map-evolver --once to trigger map breeding
- Configurable via ACB_MAP_EVOLUTION_ENABLED and ACB_MAP_EVOLUTION_SCHEDULE

This integrates map evolution into the bot evolver's deployment,
allowing weekly automated map evolution based on engagement scores
as specified in plan §14.6.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 09:15:19 -04:00
jedarden
01da007045 feat(starter-php): add PHP starter kit (acb-starter-php)
Add starters/php/ with complete starter kit for AI Code Battle:

- index.php: HTTP server with HMAC verification, routing for /turn and /health
- strategy.php: Stub compute_moves() function with example energy-seeking logic
- game.php: Game state types (GameState, Position, VisibleBot, etc.) and grid utilities (toroidal_manhattan, toroidal_chebyshev, bfs, neighbors, cardinal_steps)
- Dockerfile: Alpine-based PHP 8.4 container
- README.md: Quickstart documentation with local/Docker run instructions
- composer.json: Minimal composer config (no external dependencies)

Follows same contract as other starters:
- Listens on port 8080 (BOT_PORT env var)
- POST /turn: Receives game state JSON, returns moves JSON
- GET /health: Health check endpoint
- HMAC-SHA256 signature verification on requests/responses

Reference implementation: bots/guardian/ (GuardianBot in PHP)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 03:35:29 -04:00
jedarden
90431344e8 fix(map-evolver): add missing --once flag parsing
The --once mode was implemented but the command-line flag was not being
parsed. This commit adds the flag parsing and help text for --once, which
enables the weekly automated map evolution run from the evolver.

The evolver's weekly ticker (run.go) calls acb-map-evolver --once to
trigger map evolution on Sundays at 03:00 UTC as specified in plan §14.6.
2026-05-04 03:31:33 -04:00
jedarden
8e33ee1f27 fix(index-builder): correct function name typo in weekly chronicles generation 2026-05-04 03:10:46 -04:00
jedarden
6bfd3e6679 feat(api): implement POST /api/request-enrichment endpoint
Per plan §13.3, implements user-requested AI replay commentary with:
- HMAC bot authentication via shared_secret
- Rate limiting: 5 requests/day per bot
- Match validation (exists and completed)
- Idempotency via enrichment_requested_at column
- Enqueues to Valkey for acb-enrichment service
- Returns 202 Accepted with estimated wait time

Also adds:
- AllowN() method to ratelimit package for multi-token checks
- enrichment_requested_at column to matches table (idempotency)
- enrichLtr rate limiter (5/day per bot)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 02:58:11 -04:00
jedarden
9e566acf92 chore: update needle predispatch sha 2026-05-04 02:42:34 -04:00
jedarden
9972cb8c84 feat(matchmaker): add best-of-5 weekly featured and best-of-7 championship series scheduling
- Add 'featured' boolean column to series table for weekly featured series
- Add tickFeaturedSeries ticker that runs Friday 20:00 UTC to create bo5 featured series
- Featured series: query top 20 bots by rating, select 4 rivalry pairs by ELO proximity
- Best-of-7 championship bracket already implemented via createChampionshipBracket
- Add FeaturedSchedSecs config (default: 3600s check interval)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 02:34:47 -04:00
jedarden
df7a3e38c7 feat(worker): implement map engagement scoring per plan §14.6
Update the map engagement scoring formula to match plan §14.6:
- score = win_prob_crossings * 3.0 + critical_moments * 2.0 +
         resource_contest_turns * 1.5 + survival_turns * 0.5

New metrics computed from replay data:
- resource_contest_turns: turns where energy is contested by multiple players
- survival_turns: turns where all players have at least one bot alive

The old formula used map_coverage_pct, closeness, and turn_pct which
did not match the specification.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 02:28:45 -04:00
jedarden
e88c108010 feat(acb-enrichment): implement AI replay enrichment service
Implements the acb-enrichment service (plan §13.3) that generates AI
commentary for featured matches.

Key features:
- LLM client (OpenAI/Anthropic API compatible)
- Replay fetch from B2/R2 storage
- Structured commentary output (key_moments array with turn,
  description, significance, tags)
- Rate limiting to control LLM costs
- Match selection based on:
  - Minimum turn count
  - Win probability crossings
  - Upset threshold
  - Close finishes

Components:
- cmd/acb-enrichment/main.go - service entry point
- cmd/acb-enrichment/config.go - configuration from env vars
- cmd/acb-enrichment/service.go - orchestration logic
- internal/db/store.go - database access for match selection
- internal/llm/client.go - OpenAI-compatible LLM client
- internal/selector/selector.go - match selection with priority
- internal/generator/generator.go - commentary generation
- internal/storage/client.go - S3-compatible storage client
- Dockerfile - container image
- manifests/acb-enrichment-deployment.yml - K8s deployment
- metrics/metrics.go - Prometheus metrics for enrichment

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 02:22:28 -04:00
jedarden
c88474ad6b feat(index-builder): update community hints filter for insight/idea types
- Change filter from 'idea'/'mistake' to 'insight'/'idea' (mapping to 'hint'/'strategy' from plan §13.6)
- Increase upvote threshold from 3 to 10 for higher quality signals
- The evolver consumes community_hints.json for LLM prompt context
2026-05-04 01:38:53 -04:00
jedarden
74cbf07c78 feat(web): add progressive feature revelation library (disclosure.ts)
Implements §16.15 progressive disclosure system that reveals advanced
UI features gradually based on user engagement (XP tracked via localStorage).

Features:
- XP tracking system stored in localStorage
- reveal(featureKey) / isRevealed(featureKey) API
- 9 XP-gated features (event timeline, view modes, follow camera, etc.)
- Action-based features (predictions, sandbox, embed) unlocked by specific user actions
- Power user override to show all controls
- Engagement tracking (30+ second replay watch = 1 XP)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 01:33:09 -04:00
jedarden
ca5b20b7b7 feat(starter/csharp): complete C# starter kit with docs, tests, and Docker verification
- README.md with comprehensive setup/compile/test instructions
- Unit tests for Grid helper methods (toroidal distance, neighbors, BFS)
- Dockerfile with multi-stage build (builder, test, runtime stages)
- Verified: docker build --target test passes, HTTP endpoints work
- C# starter already indexed in web/src/pages/docs.ts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 01:26:32 -04:00
jedarden
6dd69f596d feat(api): add spam/word filter for feedback submission
Per plan §13.6, implement a configurable spam filter for the
handleCreateFeedback endpoint that:

- Validates minimum content length (default 10 chars, configurable
  via ACB_SPAM_MIN_LENGTH env var)
- Normalizes case and strips common unicode substitutions
  (leetspeak: 0→o, 1→i, 3→e, 4→a, 5→s, 7→t, @→a, $→s, etc.)
- Checks content against a block-list of banned terms with word-boundary
  matching
- Returns HTTP 422 (Unprocessable Entity) on filter rejection

Configuration:
- ACB_SPAM_BLOCK_LIST: comma-separated custom blocked terms (optional,
  defaults to embedded list of common spam/offensive words)
- ACB_SPAM_MIN_LENGTH: minimum feedback content length (default: 10)

The embedded default block-list includes:
- Profanity and offensive language
- Common spam patterns (buy now, click here, free money, etc.)
- Scam patterns (bitcoin giveaway, urgent, act now, etc.)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 01:26:32 -04:00
jedarden
39fe612f6a feat(worker): fix rating recovery default sigma value
The rating recovery CLI mode (-mode=recalc-ratings) was using
glicko2Tau (0.5) instead of glicko2DefaultSigma (0.06) for the
default sigma value when resetting ratings. This caused the reset
sigma to be ~8x higher than the schema-defined default.

Added glicko2DefaultSigma constant (0.06) and updated ResetAllRatings
and recalcRatings to use it correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 00:49:47 -04:00
jedarden
467b7b67ea feat(worker): add rating recovery CLI mode (-mode=recalc-ratings)
Implements the rating recovery procedure specified in plan §12.3.
Running 'go run ./cmd/acb-worker -mode=recalc-ratings' will:
1. Reset all bot ratings to Glicko-2 defaults (mu=1500, phi=350, sigma=0.06)
2. Fetch all completed matches from the database in chronological order
3. Replay each match to recompute Glicko-2 ratings from scratch
4. Update the bots table with the recalculated ratings

This is needed for disaster recovery when ratings are corrupted or lost.

Database functions added:
- ResetAllRatings: resets all bot ratings to defaults
- GetAllCompletedMatches: fetches completed matches chronologically with participants
- UpdateAllRatings: bulk updates all bot ratings in a single transaction

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 00:41:10 -04:00
jedarden
aeef954590 feat(index-builder): add sitemap.xml generation
Add sitemap.xml generation as a final pass in the index builder. The
sitemap covers all public pages: home, leaderboard, bots list, bot
profiles, matches list, featured replays, seasons, rivalries,
predictions, and docs.

- Add SiteURL config field (ACB_SITE_URL env var, defaults to
  https://aicodebattle.com)
- Add generateSitemap() function with proper XML encoding
- Add SitemapURL and Sitemap types for XML marshaling
- Call generateSitemap() at the end of generateAllIndexes()
- Write sitemap.xml to output directory alongside leaderboard.json

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 00:09:53 -04:00
jedarden
2022baffac feat(web): add replay-schema-v1.json downloadable schema file
Add comprehensive JSON Schema for replay format (v1) as specified in
plan §15.2. This enables third-party tooling to validate and understand
replay files programmatically.

Schema documents:
- Root replay object (format_version, match_id, config, timestamps)
- Match result (winner, reason, scores, stats)
- Player information
- Map data (walls, cores, energy nodes)
- Turn-by-turn state (bots, cores, energy, scores, events)
- Optional win probability curve and critical moments
- Event types (bot_spawned, bot_died, energy_collected, core_captured,
  combat_death, collision_death)
- Debug telemetry for bot reasoning visualization

All fields include descriptions, types, constraints, and examples.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 23:56:04 -04:00
jedarden
0f44672634 feat(engine): add TestINV6_ToroidalBounds property-based fuzz test
Implements plan §3.9 requirement for INV-6 invariant verification.
The test runs thousands of random scenarios across various grid
dimensions (30x30 to 200x200) and multiple random seeds to verify
that no bot, energy, core, or wall position ever has coordinates
outside the valid bounds [0, rows) x [0, cols).

Test coverage:
- Random wall placement with potentially out-of-bounds input
- 1000 random Wrap() calls with positions far outside bounds
- Move() operations from edge and corner positions in all directions
- Neighbors() and VisibleFrom() return value validation

The test uses a manual random-seed loop approach for maximum
control and reproducibility, testing 6 grid sizes × 10 seeds
for comprehensive coverage of the toroidal wrapping invariant.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 23:52:44 -04:00
jedarden
45b05b1188 feat(engine): add tests verifying win_prob in replays and map engagement calculation
- Add map_engagement_test.go with tests for:
  - Win prob dependency in map engagement (lead changes counted)
  - Critical moments dependency in engagement score
  - Empty/nil replay handling
  - Complete ComputeWinProbability + SetWinProbability flow

This confirms the existing implementation already correctly:
- Computes win probability via Monte Carlo rollout (100 iterations)
- Sets win_prob and critical_moments on replay before serialization
- Calculates map engagement score from win_prob_crossings and critical_moments
- Writes engagement score to maps table via UpdateMapEngagement

Task: bf-qps
2026-05-03 23:45:18 -04:00
jedarden
92576dbed4 feat(worker): add map engagement score tracking and verify win_prob in replays
- Add engine.CalculateMapEngagement() to compute map engagement scores from replay data (win_prob_crossings, critical_moments, map_coverage_pct, closeness, turn_pct)
- Add DBClient.UpdateMapEngagement() to update map engagement using rolling average
- Worker now calculates and writes map engagement scores after each match
- Add test to verify win_prob array is non-empty in produced replays

This implements the win probability Monte Carlo array storage in replay JSON
feature. The engine already called ComputeWinProbability() in MatchRunner.Run(),
so this commit adds the missing map engagement tracking.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 23:21:57 -04:00
jedarden
42e9561e46 feat(map-evolver): bias energy toward center, carve corridors to force contact
Energy node placement now uses a tiered radius distribution: 30% in the
contested central zone (0.05-0.20 from center), 40% in the mid-zone
(0.20-0.40), and 30% in the home zone (0.40-0.60). Previously nodes were
placed uniformly at 0.20-0.70, letting bots farm their home quadrant
indefinitely without crossing the midline.

After cellular automata wall generation, a 3-wide corridor is carved from
each core straight to the map center, plus a 5x5 open arena at the center
tile. This creates lanes that funnel bots into contact — replicating the key
mechanic that drove frequent fights in the original AI Challenge Ants game,
where symmetric food spawning near the midfield forced both colonies to
expand outward and collide.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 18:56:39 -04:00