Playlist curation per §10 is fully implemented in the index builder:
- generatePlaylists() writes /data/playlists/index.json and {slug}.json
- curateWeeklyHighlights() selects best-of-week by upsets, elite
clashes, marathon turns, and closest finishes (last 7 days)
- persistGeneratedPlaylists() upserts to playlists/playlist_matches DB tables
- /data/playlists/ stub files seeded for all 12 curated collections
Replay viewer improvements shipped alongside:
- WinProbPoint refactored from {p0,p1} to {probs: number[]} for N players
- renderWinProbSparkline draws one line per player with matching colors
- replay.ts updated to build probs[] from replay.win_prob arrays
- Dynamic legend generated from replay.players instead of hardcoded P0/P1
New annotation overlay component (§16.8):
- AnnotationOverlay: timeline track, per-turn list, canvas markers
- createAnnotationForm: type selector, author, body, localStorage + API
- ANNOTATION_OVERLAY_STYLES: self-contained CSS for the overlay
Evolver: add mutations_per_hour metric to Totals (live.json §14)
Types: consolidate evolution types into types.ts, re-export from api-types.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add debug telemetry UI to replay viewer with player toggles,
priority-based target markers, and stacked reasoning boxes.
Fix undefined generateTestImage in main_test.go.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Covers buildFirstMatchPerBot, isNewBotDebutFast, buildPairFrequency,
isRivalryMatchFast, and integration test for playlist generation with
the optimized lookups.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Fix deploy.go to query actual table names (series_games not series_matches,
join through series_games for seasons instead of non-existent season_matches)
- Add playlist_matches table to exempt match IDs from R2 pruning
- Pre-build lookup maps for O(1) playlist match filtering instead of O(n²)
- Enhance home page featured replay to prefer AI-enriched matches
- Add enrichment test coverage (shouldEnrich criteria validation)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implement auto-curated playlists in the index builder: 12 playlist types
(closest finishes, upsets, comebacks, marathons, rivalry classics, etc.)
with weekly highlight curation. Add DB persistence, R2 pruning exemptions,
frontend pages, and AI commentary enrichment pipeline.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The buildSpotlightPrompt function accepted a rivalries parameter but never
used it. This adds top rivalry data to the LLM prompt so the generated
Counter-Strategy Spotlight can reference active rivalries. Test updated to
verify rivalry data appears in prompt output.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The series scheduler was scheduling games and creating series_games rows,
but never updated winner_id or incremented a_wins/b_wins when individual
matches completed. This left series in perpetual "active" state since
finalizeCompletedSeries checks win counts that were never incremented.
Add updateSeriesGameResults step that:
- Finds series_games with completed matches but NULL winner_id
- Updates winner_id from match_participants
- Increments a_wins or b_wins on the series table
Called as step 0 in tickSeriesScheduler, before finalization checks.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Enhance the WASM game sandbox with production-accurate Go engine:
- Add multi-player support (2-4 players) to Go WASM engine via JS callbacks
- New acbEngine.addPlayer/clearPlayers/runMatchMulti API for N-player matches
- Sandbox auto-loads Go WASM engine in background, falls back to TS engine
- Engine selector: Auto (Go WASM → TS fallback), Go WASM only, or TS only
- Engine status indicator shows which engine is active
- Performance panel reports which engine was used
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Worker resolves open predictions after writing match results (resolvePredictions + upsertPredictorStats)
- API endpoints: POST /api/predict, GET /api/predictions/open, GET /api/predictions/history
- Frontend /watch/predictions page with polling, prediction submission, and history display
- predictor_stats table tracks streaks and accuracy per predictor
- Series format selection: fix threshold from >200 to >=200 for bo3 eligibility
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Evolution page: live polling (10s), activity feed, candidate tracking,
statistics section, island overview with live.json schema
- Series page: detailed series view with game-by-game results
- Seasons page: season list with status and champion display
- Predictions page: enhanced prediction UI with open matches
- API types: add CycleInfo, Candidate, ActivityEntry, Totals for live.json
- Embed: improved embeddable replay widget
- Mobile CSS: responsive breakpoints and bottom tab bar
- Exporter: enhanced live.json generation with full cycle/candidate data
- Matchmaker: series scheduling support with config
- Worker: additional database queries for series/season data
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- POST /api/register: bot registration with URL + shared secret validation
- GET /api/job: worker polls for next pending match job (authenticated)
- POST /api/job/:id/result: worker submits match result (winner, replay JSON)
- GET /api/replay/🆔 serve replay JSON from R2 warm cache (falls back to B2)
- GET /api/bot/🆔 bot profile JSON (rating, elo, record, metadata)
- GET /api/bots: leaderboard snapshot with pagination
- POST /api/ui-feedback: accept Agentation UI feedback
Authentication via Bearer token (worker API key). Shared secrets encrypted
with AES-256-GCM using ACB_ENCRYPTION_KEY.
Installs Python 3, Node.js/TypeScript for bot validation sandbox.
Base image includes Go; Java/Rust/PHP validation is deferred to follow-up bead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace os.ReadFile+os.WriteFile with io.Copy so large files (e.g. the 21MB
demo-replay-v2-6p.json) are never fully loaded into RAM during copyWebAssets.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a web-builder stage to the Dockerfile (Vite/TS build) and copy the
resulting dist/ into the runtime image at /app/web/dist. Call copyWebAssets
each build cycle so HTML/JS/CSS is merged into the output dir before wrangler
deploys — previously only JSON data files were uploaded, causing CF Pages to
serve 404 at the root.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wrangler creates .wrangler/tmp relative to its working directory.
The container runs as non-root user acb with WORKDIR=/app (root-owned),
so mkdir /app/.wrangler/tmp fails with EACCES. Setting cmd.Dir=/tmp
gives wrangler a writable CWD while keeping the /data output path
(absolute) unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
matches.winner is an INTEGER (player slot), not a bot_id VARCHAR.
Fix two queries that compared mp.bot_id = m.winner (type mismatch)
to use mp.player_slot = m.winner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
COALESCE(parent_ids, '[]'::json) fails because the column is JSONB
and PostgreSQL won't coerce json to jsonb. Change to '[]'::jsonb.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fixed TestSelectBestCandidate_GoHttpBonus: HTTP bonus (1.5x) on 150-char code
(225 score) doesn't beat 500-char plain text (500 score). Test now expects
the longer code to win.
- Fixed TestScoreCandidate_Bonuses: adjusted minScore expectations to match
actual code lengths with 1.5x bonus applied.
- Fixed TestBehaviorDistance: use epsilon comparison for floating-point
precision instead of exact equality. sqrt(2) ≈ 1.414214 is not exactly
representable in floating-point.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add the 'evolve' subcommand that ties together the LLM prompt builder
and ensemble components:
- Load programs from target island
- Select parents via tournament selection
- Analyze optional replay files for strategic context
- Build meta description from current ladder state
- Assemble evolution prompt with all context
- Run LLM ensemble (fast tier + strong tier refinement)
- Output generated bot code
Usage: acb-evolver evolve -island alpha -lang go [-replay file.json] [-out file.go]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add parent sampling via tournament selection (selector/tournament.go)
- Add replay analyzer to extract key moments, strategies, weaknesses
- Add meta builder for leaderboard summary and dominant strategies
- Add prompt assembler combining parent code + replay + meta context
- Add LLM ensemble with fast tier (GLM-5-Turbo) for bulk generation
and strong tier (GLM-5) for refinement passes
- Add code extraction from LLM responses with language validation
- Add convert utilities for type conversion between packages
- Comprehensive test coverage for all components
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Go implementations of 5 strategy bots directly into the engine:
- GathererBot: prioritizes energy collection, avoids combat
- RusherBot: aggressively rushes enemy cores
- GuardianBot: defends cores with cautious expansion
- SwarmBot: formation-based coordinated movement
- HunterBot: targets isolated enemy units
Update acb-local with bot selection flags:
- -bot0/-bot1: select bot strategies
- -list-bots: list available strategies
- Default to gatherer vs rusher for interesting gameplay
Enables demo replays with real strategic behavior without K8s infrastructure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Delete, List, ListTopByIsland, and GetLineage methods to the programs
Store. These complete the CRUD operations needed for the evolution pipeline:
- Delete: Remove programs by ID
- List: Paginated listing of all programs
- ListTopByIsland: Get top N programs by fitness for a specific island
- GetLineage: Recursively traverse parent chain for lineage tracking
Also adds comprehensive tests for all new operations including lineage
tracking through grandparent-parent-child chains.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Upload replays to B2 (Backblaze) instead of R2 for cold archive storage
- Write match results directly to PostgreSQL instead of HTTP API
- Perform Glicko-2 rating updates in worker after match completion
- Update config: ACB_R2_* env vars → ACB_B2_*
- Remove obsolete api_test.go (tested removed HTTP client)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cleanup of superseded code that no longer matches the architecture:
Removed:
- worker-api/ - Cloudflare Worker with D1, superseded by K8s-based matchmaker + direct PostgreSQL
- cmd/acb-indexer/ - TypeScript index builder, superseded by Go cmd/acb-index-builder/
- cluster-configuration/ - K8s manifests belong in ardenone-cluster repo
Gutted cmd/acb-api/:
- Removed registration, job claim/result endpoints (deferred for v1)
- Removed dead code: predictions.go, seasons.go, series.go, register.go, jobs.go, glicko2.go
- API is now a stub with only health/ready endpoints
- Matchmaker and workers handle the core loop without it
Updated PROGRESS.md to reflect current architecture.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add s3.go with AWS SDK v2 S3Client wrapper for R2/B2 operations
- Implement listObjects, deleteObject, objectExists, uploadFile, copyObject, downloadObject
- Add s3_test.go with MockS3Client and comprehensive tests
- Wire promoteRecentReplaysForCycle() into build cycle in main.go
- Add fetchRecentMatchIDs() to query recent matches from PostgreSQL
- Add fetchExemptMatchIDs() to protect series/season/playlist matches from pruning
- Implement pruneR2CacheWithDB() for 10GB cap enforcement with exemptions
- Update go.mod with AWS SDK v2 dependencies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add LLMBaseURL and LLMAPIKey config options for narrative generation
- Wire up LLM client to generateBlog() when LLM is configured
- Fix ParticipantData type usage in test files
- Simplify rivalry arc detection (remove alternation check)
- Fix type conversion in upset detection gap calculation
- Mark narrative engine as complete in PROGRESS.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Created narrative.go with story arc detection per plan §15.5
- Arc types: Rise, Fall, Rivalry, upset, evolution, comeback
- LLMClient for OpenAI-compatible API narrative generation
- generateLLMChronicles() using narrative engine
- Updated blog.go with LLM integration
- Template-based fallback when LLM unavailable
- Added tests in narrative_test.go
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add R2 client module (cmd/acb-evolver/internal/live/r2.go) with
S3-compatible uploads to Cloudflare R2
- UploadLiveJSON() uploads evolution state to evolution/live.json
with Cache-Control: max-age=10 for near-real-time updates
- Add -r2 and -r2-only flags to live-export subcommand
- Add tests for R2 config validation and credential handling
- Update frontend to fetch live data from R2 URL instead of Pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add blog generation to Go index builder (cmd/acb-index-builder/blog.go):
- Weekly meta report generation with competitive analysis
- Story arc chronicles: rise stories, upsets, rivalries
- Blog index and individual post JSON generation
- Add blog page to web SPA (web/src/pages/blog.ts):
- Blog listing with type filters (all/meta-report/chronicle)
- Individual post view with markdown rendering
- Tag cloud and post metadata display
- Added /blog and /blog/:slug routes
- Add Blog link to navigation menu
- Add placeholder blog data files for initial content
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Canvas-rendered PNG card generation in cmd/acb-index-builder/cards.go
- 1200x630 images for social sharing (OG/Twitter)
- Rating tiers with color coding (gold/silver/bronze/green/gray)
- Win rate color coding (green/blue/yellow/red)
- Rank badges for top 100 bots
- Evolved bot badges with island indicator
- Add card upload to R2 warm cache and B2 cold archive
- Add Open Graph meta tags in web/app.html
- Add dynamic OG tag management in web/src/og-tags.ts
- Update bot profile page to set OG tags on load
- Add BuildTimeout config field (fixes test failures)
- Add comprehensive tests for card generation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per plan §11.1, the index builder reads PostgreSQL and generates all JSON
index files for Cloudflare Pages deployment:
- main.go: Build cycle orchestration with configurable timeout, self-restart
- config.go: Environment-based configuration with sensible defaults
- db.go: PostgreSQL data fetching for bots, matches, series, seasons, predictions
- generator.go: JSON index generation (leaderboard, bots, matches, playlists)
- deploy.go: Cloudflare Pages deployment via wrangler, R2 warm cache pruning
- Dockerfile: Multi-stage build with Go + Node.js + wrangler CLI
- main_test.go: Tests for config, index generation, playlists
Index builder runs on 15-minute cycles, deploys to Pages every ~90 minutes,
and prunes R2 warm cache weekly to stay within 10GB free tier.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Embeddable Replay Widget:
- web/embed.html: Minimal standalone HTML with Open Graph and Twitter Card tags
- web/src/embed.ts: TypeScript embed viewer with auto-play, progress bar, keyboard controls
- R2 warm cache + B2 cold archive fallback for replay loading
- ~7KB gzipped (well under 50KB target)
Replay Playlists:
- cmd/acb-indexer/src/playlists.ts: Auto-curated playlist generator
- Featured, upsets, comebacks, domination, close games, long games, weekly categories
- Uses match data to detect notable games
- web/src/pages/playlists.ts: SPA page for browsing playlists
- web/src/api-types.ts: Added playlist types and fetch functions
Other changes:
- web/src/replay-viewer.ts: Added getIsPlaying() method for embed viewer
- web/vite.config.ts: Added embed.html as build entry point
- web/app.html: Added Playlists nav link
- web/public/img/embed-placeholder.svg: OG image placeholder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Architecture conformance fix per plan §12 Phase 4:
- Plan specifies Matchmaker Deployment as internal service with no external exposure
- Extracted tickers.go from acb-api to new cmd/acb-matchmaker/
- Tickers: bot pairing (1 min), health checking (15 min), stale job reaping (5 min)
- Alerting webhooks moved from acb-api to acb-matchmaker
- Created Dockerfile for acb-matchmaker container
- Created K8s deployment manifest (no service needed - internal only)
- Fixed syntax error in cmd/acb-api/db.go (prematurely closed schemaSQL string)
This separates concerns per the plan:
- acb-api: HTTP endpoints for bot registration, job coordination, bot status
- acb-matchmaker: Internal tickers for matchmaking, health checks, reaping
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- arena/arena.go: 10-match mini-tournament running candidate as a local
subprocess against diverse live opponents sampled across the rating
distribution; AES-GCM secret decryption for opponent auth
- arena/psro.go: Nash equilibrium computation for the 1×K meta-game;
FictitiousPlayNash included for future K×K support
- arena/winrate.go: Wilson-score 95% CI for win-rate calculation; draws
counted as 0.5 wins
- arena/gate.go: two-part promotion gate — Nash value ≥ threshold AND
MAP-Elites niche fill or improvement; detailed reason strings
- promoter/promoter.go: full promotion pipeline — bot source + Dockerfile
+ K8s Secret/Deployment/Service manifests, docker build, git commit/push
(ArgoCD sync), kubectl readiness poll, bots-table INSERT, programs-table
update; RetireBot and EnforcePolicy (rating threshold + population cap 50)
- db/db.go: add bot_name / bot_secret migration columns
- db/programs.go: ListPromoted, SetBotNameAndSecret, UnsetPromoted,
GetByBotID, PromotedCount helpers for promotion/retirement lifecycle
- main.go: evaluate and retire subcommands wiring arena + gate + promoter;
remove unused island flag from evaluate
- arena/arena_test.go: 21 unit tests covering Nash, Wilson CI, Gate logic,
and selectDiverse opponent sampling
- promoter/promoter_test.go: tests for Dockerfiles, bot-ID/secret generation,
AES-GCM helpers, and K8s manifest templates
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- selector: tournament selection for parent sampling from island populations
- prompt: assembles evolution prompts from parent code, replay analysis, and meta description
- llm: OpenAI-compatible client routing to ZAI proxy with fast (GLM-5-Turbo) and strong (GLM-5) tiers, plus code block extraction from model responses
- Tests for prompt assembly, code extraction, and tournament selection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements the monitoring alerting deliverable from Phase 6. The Alerter
module sends color-coded notifications to Discord and/or Slack webhooks
for operational events: bot health transitions, stale job re-enqueues,
and match errors. Includes per-key rate limiting to prevent alert storms.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements the K8s-native Go API service per the plan architecture:
- HTTP server with graceful shutdown and env-var configuration
- PostgreSQL schema (bots, matches, match_participants, jobs, rating_history)
- Health/ready endpoints checking PostgreSQL and Valkey connectivity
- Bot registration with health check, HMAC secret gen, AES-256-GCM encryption
- Key rotation and bot status endpoints
- Job claim via Valkey BRPOP, result submission with Glicko-2 rating update
- Glicko-2 rating system: multi-player pairwise, Illinois volatility algorithm
- Background tickers: matchmaker (1m), health checker (15m), stale job reaper (5m)
- Worker API key authentication (Bearer/X-API-Key)
- Dockerfile, K8s Deployment (2 replicas), ClusterIP Service
- 30 unit tests covering Glicko-2, crypto, config, and handlers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace broken Taylor series sin/cos approximations with math.Sin/math.Cos
in both engine/match.go and cmd/acb-mapgen. The Taylor series produced
incorrect results for angles > π, causing wrong positions in 3+ player maps.
Upgrade map generator wall placement from random scatter to cellular
automata (B5/S4 rule, 4 iterations) with rotational symmetry enforcement
and connectivity validation. Add comprehensive mapgen tests and dominance
win condition tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a metrics HTTP server to acb-worker exposing Prometheus text format
at /metrics, plus /health and /ready K8s probe endpoints. Tracks counters
(matches, errors, jobs, replays, polls, heartbeats) and histograms
(match duration, replay upload duration, replay size). Instruments the
full worker execution flow. Fixes .gitignore binary patterns to use
root-anchored paths so cmd/ subdirectories aren't incorrectly excluded.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add comprehensive .gitignore for binaries, node_modules, and build outputs
- Add package-lock.json for cmd/acb-indexer and worker-api
- Ensures reproducible builds with exact dependency versions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Dockerfile for acb-worker match execution container
- Add docker-compose.bots.yml for orchestrating all 6 strategy bots
- Add docker-compose.workers.yml for worker and indexer deployment
- Add .env.example documenting all required environment variables
- Add DEPLOYMENT.md with deployment guide and troubleshooting
- Update PROGRESS.md with Phase 6 progress
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add /api/data/export endpoint to worker-api for data export
- Create cmd/acb-indexer/ TypeScript container:
- API client for fetching data from Worker API
- Index generator for leaderboard, bot profiles, match index
- File writer for outputting JSON files
- Optional Cloudflare Pages deploy support
- Unit tests (6 tests)
- Update PROGRESS.md to mark Phase 4 complete
Phase 4 is now complete. All exit criteria met:
- Matchmaker cron creates jobs in D1
- Workers claim and execute matches
- Replays land in R2
- Results flow into D1
- Ratings update via Glicko-2
- Leaderboard.json rebuilds automatically
- Stale job reaper recovers from worker disappearance
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>