feat: AI-game refinements (GCG, your_turn, admin, metrics)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 49s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m7s

Follow-ups on the honest-AI game, same PR:
- GCG export labels the robot seat "AI" instead of its pool name (ExportGCG
  overrides via accounts.IsRobot); the in-app 🤖 is unchanged.
- vs_ai games emit no your_turn (the robot replies instantly, so it would be
  redundant); opponent_moved still advances the UI.
- Admin console shows the AI flag: a 🤖 column in /games and an "AI game" line
  on the game card (GameRow/GameDetailView gain VsAI).
- games_started_total / games_abandoned_total gain a vs_ai attribute; the
  Grafana Game-domain dashboard splits started/abandoned into human and AI
  panels.

Tests: metrics unit (vs_ai split); integration (no your_turn, GCG "AI").
This commit is contained in:
Ilia Denisov
2026-06-15 20:49:49 +02:00
parent aa765a0c06
commit d2a9441287
12 changed files with 166 additions and 41 deletions
+15 -5
View File
@@ -4,24 +4,34 @@
"tags": ["scrabble"],
"timezone": "",
"schemaVersion": 39,
"version": 2,
"version": 3,
"refresh": "30s",
"time": { "from": "now-24h", "to": "now" },
"panels": [
{
"type": "timeseries",
"title": "Games started / abandoned (rate by variant)",
"title": "Games started / abandoned — human (rate by variant)",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{ "refId": "A", "expr": "sum(rate(games_started_total[15m])) by (variant)", "legendFormat": "started {{variant}}" },
{ "refId": "B", "expr": "sum(rate(games_abandoned_total[15m])) by (variant)", "legendFormat": "abandoned {{variant}}" }
{ "refId": "A", "expr": "sum(rate(games_started_total{vs_ai=\"false\"}[15m])) by (variant)", "legendFormat": "started {{variant}}" },
{ "refId": "B", "expr": "sum(rate(games_abandoned_total{vs_ai=\"false\"}[15m])) by (variant)", "legendFormat": "abandoned {{variant}}" }
]
},
{
"type": "timeseries",
"title": "Games started / abandoned — AI (rate by variant)",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 },
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{ "refId": "A", "expr": "sum(rate(games_started_total{vs_ai=\"true\"}[15m])) by (variant)", "legendFormat": "started {{variant}}" },
{ "refId": "B", "expr": "sum(rate(games_abandoned_total{vs_ai=\"true\"}[15m])) by (variant)", "legendFormat": "abandoned {{variant}}" }
]
},
{
"type": "timeseries",
"title": "Robot games finished (rate)",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 },
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 24 },
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [{ "refId": "A", "expr": "sum(rate(robot_games_finished_total[15m]))", "legendFormat": "robot games" }]
},