Commit graph

19 commits

Author SHA1 Message Date
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
c726de4d7c fix(test): replace duration-based age check with calendar-relative anchors
TestThreeMonthAgeCheck used 89*24h as "3 months minus 1 day", but
89 calendar days == exactly 3 months on dates like May 1 (Feb+Mar+Apr=
28+31+30=89). The equality case makes the >3-month eligibility check
return true instead of false. Replace with AddDate-relative anchors
so the test stays correct regardless of current date.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 22:14:40 -04:00
jedarden
ea2f1b50b7 fix(matchmaker): stale-reaper queries claimed not running status
Jobs remain in 'claimed' status until completed — the reaper was
querying 'running' (which is the match status, not job status) so
stale claimed jobs were never recycled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:24:57 -04:00
jedarden
d0087a3241 fix(docker): add COPY metrics/ to all service Dockerfiles
The metrics package is a local module dependency imported by all services
but was missing from every Dockerfile's build context.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 18:00:16 -04:00
jedarden
002f945298 fix(matchmaker): use inclusive boundary for classic promotion age check
90 days == 3 calendar months exactly in March/April, causing
TestThreeMonthAgeCheck to fail. The intent is >= 3 months old.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 17:45:36 -04:00
jedarden
3b94b7eccb feat(matchmaker): add map fairness monitoring and auto-retirement (§14.6)
Implements the full map lifecycle audit as a hourly ticker in the
matchmaker:

1. updateMapFairnessStats: recompute per-slot win counts from completed
   matches into the map_fairness table
2. flagUnfairMaps: flag maps where any slot deviates >10pp from expected
   (1/N) across 80+ matches → status='probation'
3. retireDislikedMaps: force-retire maps with >20 net negative votes
4. pruneLowEngagementMaps: monthly bottom-10% engagement prune per tier
5. promoteClassicMaps: top-5 all-time engagement, 3+ months → 'classic'

Matchmaker already filters retired maps and gives probation maps 50%
reduced selection probability in selectMapLRU.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 18:19:24 -04:00
jedarden
6c1f031071 feat(config): add season_id + rules_version to Config per §4.2
- SeasonID and RulesVersion already present in engine/types.go Config struct
- Worker already populates from active season row via DB join
- Config embedded in VisibleState sent to bots each turn (including turn 0)
- All starter kits (go, python, rust, java, csharp) already expose and log fields
- Add season_id/rules_version logging to JavaScript starter on turn 0
- TypeScript Config interface already includes season_id and rules_version

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 18:09:26 -04:00
jedarden
b2e9ba8319 fix(matchmaker): correct priority inversion in bestCandidate opponent selection
The bestCandidate function allowed game count to override pairing recency
when both candidates had non-zero LastPairedAt values. Per §6.1, pairing
recency must be the primary criterion with game count only breaking ties.

Also adds 10 tests covering: never-paired preference, oldest-pairing
preference, game count tiebreaking, Pareto distribution verification,
multi-opponent selection, and regression test for the priority inversion.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 17:46:44 -04:00
jedarden
477a54c548 feat(matchmaker): implement §6.1 Pareto skill-proximity + LRU pairing algorithm
Replace random 2-player pairing with the full §6.1 algorithm:
- Seed selection: bot with oldest last-match timestamp (tiebreak: lowest bot ID)
- Format selection: seed's least-played player count among {2, 3, 4, 6}
- Opponent selection: Pareto 80%/16-rank skill proximity + oldest last-pairing
  with seed + fewest 24h games for game-count balance
- Map selection: least-recently-used active map for the chosen player count,
  with map_scores.last_used_at updated after each match
- Random player slot assignment for all participant counts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 17:35:00 -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
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
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
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
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
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
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
875ccdbe83 Extract matchmaker into separate deployment (acb-matchmaker)
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>
2026-03-29 00:55:46 -04:00