Commit graph

67 commits

Author SHA1 Message Date
jedarden
7e131d310f feat(api): add token-bucket rate limiting to public endpoints
Adds ratelimit package with per-IP and per-key HTTP middleware.
Applied to register (5/hr), feedback (20/hr), predict (60/hr),
and job submission (5/day) endpoints. Includes metrics counter
for rejected requests and periodic bucket cleanup goroutine.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 16:52:29 -04:00
jedarden
5a1130c77a feat(bot): add Pacifist bot (JavaScript) — non-aggressive attrition archetype
PacifistBot never attacks; it survives by maximizing distance from enemies
and retreating toward own core when cornered. Pure evasion strategy that
wins via opponent elimination by third parties.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 16:32:50 -04:00
jedarden
7f2407ed00 feat: add Prometheus metrics instrumentation across services
Add metrics server startup and HTTP middleware to acb-api, generation
counter metric to evolver, and R2 cache size metric to index builder.

Also remove dead measureR2CacheSize reference from index builder main.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 16:16:03 -04:00
jedarden
fff795ba6c fix(index-builder): improve rivalry recency test isolation + add metrics
The RecencyBoost test now uses balanced 5-5 splits for both pairs so
recency is the sole differentiating factor (previously one pair was 10-0
which conflated balance and recency). Also wires Prometheus build
duration metric in main loop.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 16:07:18 -04:00
jedarden
7a0de02059 feat(evolver): persist cross-pollination state to Postgres per §10.2
Add crosspoll_state table to persist per-island generation counters
across evolver restarts. Load state on startup and save after each
cross-pollination check. Add persistence pattern and translation
structure tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 16:04:15 -04:00
jedarden
582b4c010d fix(worker): remove unused net/http import in acb-worker
Pre-existing issue blocking go vet and go test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:55:45 -04:00
jedarden
80334c6e34 feat(evolver): expand MAP-Elites from 2-D to 4-D grid per §10.2
- Add Exploration and Formation axis definitions with feature extraction
  from source code pattern matching (exploration/formation indicators)
- Extend Grid key from (x,y) to (x,y,z,w) with 3⁴=81-cell behavior grid
- Update bin assignment, promotion gate, and persistence (JSON snapshot)
- Add Slice() for 2-D dashboard visualization across any axis pair
- Migration: old 2-D archives project at z=middle, w=middle
- Update cross-pollination to pad 2-element behavior vectors to 4
- Add Prometheus metrics to matchmaker (bot crashes, stale job count)
- Add rivalry detection to index builder (data/meta/rivalries.json)
- Web: batched bot list loading, leaderboard keyboard accessibility,
  improved ARIA attributes on match/playlist cards

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:44:39 -04:00
jedarden
e90d2e37c9 test(evolver): integration tests for cross-pollination logic per §10.2
Adds mock store/LLM implementations and tests for CheckAndPollinate:
generation boundaries, fitness penalties, translation triggers,
multi-boundary catch-up, and empty island handling.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:26:18 -04:00
jedarden
c56cc8bae6 fix(matchmaker): multi-match crash cooldown (3 strikes / 30 min) per §4.5 + §6.1
Add crash_strikes and cooldown_until columns to bots table. Worker
increments strikes on crash (cooldown at 3), resets on success.
Matchmaker excludes cooldown bots from pairing, series scheduling,
and championship brackets. Fix erroneous cooldown filter on series
table in finalizeCompletedSeries (column only exists on bots).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:22:12 -04:00
jedarden
fb707b8461 test: integration tests for multi-match crash cooldown (3 strikes / 30 min) per §4.5 + §6.1
The crash cooldown system was already implemented across engine, worker,
and matchmaker. This adds comprehensive integration tests that verify:

- Single crash does not trigger cooldown
- Two crashes do not trigger cooldown
- Three consecutive crashes trigger 30-min cooldown
- Successful match resets strike counter
- Interleaved crash/success resets counter correctly
- Cooldown extends on repeated crashes while on cooldown
- Matchmaker eligibility query excludes bots on active cooldown
- Matchmaker eligibility query includes bots with expired cooldown
- Full end-to-end flow: 3 crashes → excluded → cooldown expires → re-pair

Tests use ACB_TEST_DATABASE_URL env var for PostgreSQL integration tests
and skip gracefully when not configured.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:14:03 -04:00
jedarden
d43cf83471 feat(evolver): island cross-pollination every 50 generations per §10.2
Adds cross-pollination logic that copies the top program from each island
to a random other island every 50 generations. When source and target
islands use different languages, the LLM translates the code. Generation
boundaries are tracked per-island to prevent duplicate events.

- New crosspoll package with boundary detection, migration, and LLM translation
- Added MaxGenerationByIsland DB query for generation counter tracking
- Integrated into RunEvolutionLoop with observability logging
- Tests for boundary logic, translation prompts, and target selection

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:13:27 -04:00
jedarden
c618f0b7a1 feat(worker): gzip replay compression at upload per §7.1
Worker now gzip-compresses replays before uploading to B2 with
key replays/{match_id}.json.gz and Content-Encoding: gzip.
Updated B2 client Upload to accept contentEncoding parameter.
Fixed downstream web consumers (matches, bot-profile, playlists)
to reference .json.gz URLs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 15:00:09 -04:00
jedarden
81940a1598 fix(api): fix getEnv stub and Dockerfile Go version for deployment readiness
The getEnv() function in server.go always returned the default value,
preventing ACB_R2_ENDPOINT/ACB_B2_ENDPOINT from being read at runtime.
Also updated Dockerfile from golang:1.24 to golang:1.25 to match go.mod.

K8s manifests for acb-evolver and acb-api already exist in
declarative-config/k8s/iad-acb/ai-code-battle/ (added Apr 21).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 13:29:45 -04:00
jedarden
f6ce4588f4 fix(api): rename /api/ui-feedback to /api/feedback per plan §13.6
The community feedback endpoint was registered as /api/ui-feedback in
the Go API but the plan and annotation.ts client both use /api/feedback.
Rename the route and update agentation-overlay.ts to match. Add a
route-level test asserting the canonical path and that the old path
returns 404.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 13:22:47 -04:00
jedarden
d8812b98ee feat(playlists/replay): n-player win prob, annotations, evolver metrics
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>
2026-04-21 17:15:31 -04:00
jedarden
80af92b022 feat(replay): add debug telemetry panel and fix test build
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>
2026-04-21 16:57:15 -04:00
jedarden
80040fa501 test(index-builder): add tests for fast playlist lookup helpers
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>
2026-04-21 16:48:20 -04:00
jedarden
be3843d9ac fix(index-builder): correct series/season exempt queries, optimize playlist curation
- 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>
2026-04-21 16:47:13 -04:00
jedarden
b1121ed6f8 feat(playlists): add playlist curation and rebuild logic per §10, with series/seasons/enrichment
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>
2026-04-21 16:11:27 -04:00
jedarden
70b7337867 feat(blog): add rivalry context to spotlight prompt and fix narrative tests
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>
2026-04-21 15:45:33 -04:00
jedarden
1796f2a27e feat(matchmaker): add series game result propagation to scheduler
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>
2026-04-21 15:31:33 -04:00
jedarden
51edf35d22 feat(sandbox): integrate Go WASM engine with multi-player support per §13.1
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>
2026-04-21 15:28:35 -04:00
jedarden
347ae4f1df feat(predictions): resolve predictions on match completion, add API endpoints and frontend
- 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>
2026-04-21 14:08:15 -04:00
jedarden
91d807cec2 feat(web,cmd): enhance evolution dashboard, series/seasons pages, and matchmaker
- 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>
2026-04-21 13:42:20 -04:00
jedarden
5215cd7e57 fix(web): remove unused colors parameter from drawThreatLines call
- Minor fix to match function signature
- Add lazy loaders for feedback and docs-api pages
2026-04-21 09:02:22 -04:00
jedarden
00069b1870 feat(acb-api): implement bot registration, job coordination, and replay endpoints per plan §12 Phase 4
- 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.
2026-04-21 08:58:42 -04:00
jedarden
3b8bd66575 feat(acb-evolver): add Dockerfile for evolver container with multi-language runtime support
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>
2026-04-21 08:41:10 -04:00
jedarden
dcdca5147f fix(index-builder): stream-copy web assets to avoid large-file OOM
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>
2026-04-21 07:35:42 -04:00
jedarden
498cd0e5d7 fix(index-builder): include web frontend in Pages deployment
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>
2026-04-21 07:23:45 -04:00
jedarden
82d5ecba1f fix(index-builder): set wrangler CWD to /tmp for Pages deploy
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>
2026-04-21 07:03:20 -04:00
jedarden
6743d1f670 fix(index-builder): use player_slot when comparing to matches.winner
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>
2026-04-20 23:37:22 -04:00
jedarden
5b23a83ad4 fix(index-builder): cast parent_ids default to jsonb
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>
2026-04-20 23:32:28 -04:00
jedarden
f206a87575 fix(db): add missing columns to jobs and bots schema
jobs: add heartbeat_at and created_at columns needed by acb-worker
bots: add archetype column needed by acb-index-builder

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 23:29:18 -04:00
Argo Workflows CI
6142262edd fix(acb-index-builder): use GID 1001 to avoid conflict with node user (GID 1000) in node:22-alpine 2026-04-14 13:51:51 -04:00
Argo Workflows CI
be5ffbf8c1 fix: update Dockerfiles to golang:1.25-alpine (go.mod requires go 1.25.0) 2026-04-14 13:43:39 -04:00
jedarden
4ba39e3aa8 feat(evolver): complete Phase 7 LLM-driven evolution implementation
- Complete autonomous evolution pipeline with island model (4 islands)
- MAP-Elites behavior grid integration for diversity
- LLM ensemble integration (fast + strong model tiers)
- 3-stage validation pipeline (syntax → schema → sandbox smoke test)
- Evaluation arena (10-match mini-tournament per candidate)
- Promotion gate (Nash equilibrium PSRO + MAP-Elites niche fill)
- Retirement policy (auto-retire low-rated bots, population cap)
- Live export to R2 for evolution dashboard
- Enhanced replay viewer with commentary and win probability
- Added series, seasons, and predictions pages

All tests passing. Phase 7 exit criteria met.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 16:38:48 -04:00
jedarden
f3e34c6736 fix(evolver): correct failing tests for ensemble and behavior distance
- 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>
2026-04-08 16:36:50 -04:00
jedarden
b191751c2b feat(acb-evolver): add evolve CLI command for LLM-based bot generation
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>
2026-03-29 19:14:17 -04:00
jedarden
f5924e8b15 feat(acb-evolver): add LLM prompt builder and ensemble integration
- 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>
2026-03-29 16:47:25 -04:00
jedarden
df3e59b9a9 feat(acb-local): add strategy bots for offline matches
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>
2026-03-29 14:27:36 -04:00
jedarden
3d9326d767 feat(acb-evolver): add CRUD operations for programs database with island model
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>
2026-03-29 12:08:21 -04:00
jedarden
729efb3f45 Refactor acb-worker: B2 uploads, PostgreSQL writes, Glicko-2 ratings
- 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>
2026-03-29 10:46:23 -04:00
jedarden
b06350d762 Remove legacy code: worker-api/, cmd/acb-indexer/, cluster-configuration/, gut cmd/acb-api/
Some checks failed
CI / Go Tests (push) Has been cancelled
CI / Worker API Tests (push) Has been cancelled
CI / Indexer Tests (push) Has been cancelled
CI / Web Build (push) Has been cancelled
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>
2026-03-29 10:22:16 -04:00
jedarden
21308dce05 Implement S3 functions for R2/B2 integration in acb-index-builder
- 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>
2026-03-29 09:09:29 -04:00
jedarden
5356c8ee0a Integrate LLM client with blog generation (Phase 10)
- 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>
2026-03-29 06:54:02 -04:00
jedarden
44544622ae Phase 10 Narrative Engine Implementation
- 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>
2026-03-29 06:35:36 -04:00
jedarden
1523c52e0a Add R2 upload for live evolution observatory (Phase 10)
- 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>
2026-03-29 04:53:35 -04:00
jedarden
c07eb1f2eb Add blog infrastructure for weekly meta reports (Phase 10)
- 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>
2026-03-29 04:39:12 -04:00
jedarden
88a5893f66 Add bot profile cards with Open Graph support (Phase 9 complete)
- 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>
2026-03-29 03:30:46 -04:00
jedarden
70bde20472 Add Go index builder (cmd/acb-index-builder)
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>
2026-03-29 03:15:47 -04:00