Add monthly player ranking data audit
This commit is contained in:
98
ai/tasks/done/TASK-065-monthly-player-ranking-data-audit.md
Normal file
98
ai/tasks/done/TASK-065-monthly-player-ranking-data-audit.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# TASK-065-monthly-player-ranking-data-audit
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Auditar con precisión los datos disponibles actualmente en el proyecto y en la fuente histórica CRCON/scoreboard para determinar qué métricas pueden alimentar un futuro ranking mensual de mejores jugadores y con qué nivel de fiabilidad.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
Se quiere diseñar un futuro ranking de “Top 3 mejores jugadores del mes”, idealmente teniendo en cuenta variables como:
|
||||||
|
- kills
|
||||||
|
- KPM
|
||||||
|
- KDA
|
||||||
|
- apoyo
|
||||||
|
- garrisons/OPs quitados si estuvieran disponibles
|
||||||
|
- enfrentamientos directos si fueran extraíbles
|
||||||
|
- impacto en partida
|
||||||
|
|
||||||
|
Pero antes de diseñar el ranking o asignar pesos, es imprescindible saber exactamente:
|
||||||
|
1. qué datos ya están persistidos en la base local del proyecto
|
||||||
|
2. qué datos existen en la fuente CRCON/scoreboard pero aún no guardamos
|
||||||
|
3. qué datos no están realmente disponibles o no son fiables
|
||||||
|
4. qué combinación de métricas sería viable para una primera versión realista del ranking
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
1. Revisar el modelo histórico actual del proyecto, incluyendo:
|
||||||
|
- tablas SQLite
|
||||||
|
- modelos históricos
|
||||||
|
- payloads
|
||||||
|
- snapshots existentes
|
||||||
|
2. Inventariar qué métricas están ya disponibles y persistidas hoy por:
|
||||||
|
- jugador
|
||||||
|
- partida
|
||||||
|
- jugador por partida
|
||||||
|
3. Confirmar con precisión qué campos existen ya en el histórico bruto y qué calidad tienen para un ranking serio.
|
||||||
|
4. Revisar la fuente histórica CRCON/scoreboard que usa el proyecto para verificar si, además de lo ya persistido, existen datos accesibles sobre:
|
||||||
|
- garrisons destruidos
|
||||||
|
- OPs destruidos
|
||||||
|
- enfrentamientos directos / duelos
|
||||||
|
- otras métricas útiles de impacto táctico
|
||||||
|
5. Documentar para cada métrica potencial:
|
||||||
|
- si ya existe en la base
|
||||||
|
- si existe en la fuente pero no se persiste aún
|
||||||
|
- si no existe realmente o no puede extraerse de forma fiable
|
||||||
|
- si sería recomendable usarla en una futura V1 del ranking
|
||||||
|
6. Dejar una matriz clara de disponibilidad y fiabilidad, por ejemplo:
|
||||||
|
- métrica
|
||||||
|
- disponible hoy
|
||||||
|
- persistida hoy
|
||||||
|
- calidad/fiabilidad
|
||||||
|
- coste de implementación adicional
|
||||||
|
- recomendable para V1 sí/no
|
||||||
|
7. Incluir una recomendación final sobre qué conjunto de métricas sería razonable para:
|
||||||
|
- una V1 del ranking mensual
|
||||||
|
- una posible V2 más ambiciosa
|
||||||
|
8. No diseñar todavía la fórmula final del ranking salvo una recomendación muy preliminar si ayuda a contextualizar.
|
||||||
|
9. No implementar todavía nuevas tablas, nuevas ingestas ni nuevas vistas de UI.
|
||||||
|
10. Al completar la implementación:
|
||||||
|
- dejar el repositorio consistente
|
||||||
|
- hacer commit
|
||||||
|
- hacer push al remoto si el entorno lo permite
|
||||||
|
|
||||||
|
## Files to Read First
|
||||||
|
- AGENTS.md
|
||||||
|
- ai/repo-context.md
|
||||||
|
- ai/architecture-index.md
|
||||||
|
- backend/README.md
|
||||||
|
- backend/app/historical_models.py
|
||||||
|
- backend/app/historical_storage.py
|
||||||
|
- backend/app/historical_ingestion.py
|
||||||
|
- backend/app/historical_snapshots.py
|
||||||
|
- backend/app/payloads.py
|
||||||
|
- docs/historical-domain-model.md
|
||||||
|
- docs/historical-data-quality-notes.md
|
||||||
|
- docs/historical-crcon-source-discovery.md
|
||||||
|
- docs/historical-coverage-report.md
|
||||||
|
- cualquier evidencia de endpoints o JSON reales de la fuente CRCON/scoreboard que ya use el proyecto
|
||||||
|
|
||||||
|
## Expected Files to Modify
|
||||||
|
- un documento nuevo, por ejemplo:
|
||||||
|
- docs/monthly-player-ranking-data-audit.md
|
||||||
|
- opcionalmente ai/architecture-index.md si conviene enlazar esta auditoría
|
||||||
|
- opcionalmente docs/decisions.md si surge una decisión técnica clara sobre el alcance de métricas para V1/V2
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- No implementar todavía el ranking mensual.
|
||||||
|
- No modificar producto visible.
|
||||||
|
- No crear nuevas rutas, vistas ni snapshots de ranking MVP.
|
||||||
|
- No hacer cambios destructivos.
|
||||||
|
- Mantener el trabajo centrado en discovery, inventario y recomendación técnica.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
- Existe un documento claro que explica exactamente con qué datos podemos contar hoy.
|
||||||
|
- Queda claro qué métricas ya están persistidas y cuáles no.
|
||||||
|
- Queda claro qué métricas existen en la fuente CRCON/scoreboard pero requerirían trabajo adicional.
|
||||||
|
- Existe una recomendación técnica razonable para una V1 y una V2 del ranking mensual de jugadores.
|
||||||
|
- Los cambios quedan committeados y se hace push si el entorno lo permite.
|
||||||
|
|
||||||
|
## Change Budget
|
||||||
|
- Preferir menos de 4 archivos modificados o creados.
|
||||||
|
- Preferir menos de 220 líneas cambiadas.
|
||||||
246
docs/monthly-player-ranking-data-audit.md
Normal file
246
docs/monthly-player-ranking-data-audit.md
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
# Monthly Player Ranking Data Audit
|
||||||
|
|
||||||
|
## Validation Date
|
||||||
|
|
||||||
|
- 2026-03-24
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
Auditoria tecnica del estado real de datos para un futuro ranking mensual de
|
||||||
|
"mejores jugadores" usando:
|
||||||
|
|
||||||
|
- codigo y esquema historico del backend
|
||||||
|
- persistencia local en `backend/data/hll_vietnam_dev.sqlite3`
|
||||||
|
- snapshots historicos ya generados en `backend/data/snapshots/`
|
||||||
|
- discovery ya documentada de la fuente CRCON/scoreboard
|
||||||
|
|
||||||
|
No se implementa todavia ninguna formula de ranking, tabla nueva ni cambio de
|
||||||
|
UI.
|
||||||
|
|
||||||
|
## Evidence Reviewed
|
||||||
|
|
||||||
|
- `backend/app/historical_models.py`
|
||||||
|
- `backend/app/historical_storage.py`
|
||||||
|
- `backend/app/historical_ingestion.py`
|
||||||
|
- `backend/app/historical_snapshots.py`
|
||||||
|
- `backend/app/historical_snapshot_storage.py`
|
||||||
|
- `backend/app/payloads.py`
|
||||||
|
- `docs/historical-domain-model.md`
|
||||||
|
- `docs/historical-data-quality-notes.md`
|
||||||
|
- `docs/historical-crcon-source-discovery.md`
|
||||||
|
- `docs/historical-coverage-report.md`
|
||||||
|
|
||||||
|
## Current Persisted State
|
||||||
|
|
||||||
|
Local SQLite currently contains:
|
||||||
|
|
||||||
|
- `historical_servers`: `3`
|
||||||
|
- `historical_matches`: `9638`
|
||||||
|
- `historical_players`: `163506`
|
||||||
|
- `historical_player_match_stats`: `1062244`
|
||||||
|
- `historical_ingestion_runs`: `32`
|
||||||
|
|
||||||
|
Coverage visible in the local database today:
|
||||||
|
|
||||||
|
- `comunidad-hispana-01`: `8602` matches, from `2024-05-17T20:48:40Z` to `2026-03-23T16:01:20Z`
|
||||||
|
- `comunidad-hispana-02`: `753` matches, from `2025-11-04T17:10:19Z` to `2026-03-23T18:58:06Z`
|
||||||
|
- `comunidad-hispana-03`: `283` matches, from `2026-01-14T22:34:18Z` to `2026-03-08T18:11:52Z`
|
||||||
|
|
||||||
|
Important quality notes from the local dataset:
|
||||||
|
|
||||||
|
- all `historical_player_match_stats` rows have populated values for kills,
|
||||||
|
deaths, teamkills, time, KPM, KDA, combat, offense, defense, support, level
|
||||||
|
and team side
|
||||||
|
- `85,270 / 163,506` players have SteamID; the rest currently depend on
|
||||||
|
`crcon-player:*` identity, so identity continuity is usable but not equally
|
||||||
|
strong for every player
|
||||||
|
- all persisted matches have start/end timestamps, map and game mode
|
||||||
|
- `7,961 / 9,638` persisted matches currently have both allied/axis score
|
||||||
|
|
||||||
|
## What Is Persisted Today
|
||||||
|
|
||||||
|
### Match level
|
||||||
|
|
||||||
|
Persisted per match:
|
||||||
|
|
||||||
|
- server
|
||||||
|
- external match id
|
||||||
|
- creation/start/end timestamps
|
||||||
|
- map name, pretty name, game mode, image
|
||||||
|
- allied score
|
||||||
|
- axis score
|
||||||
|
|
||||||
|
Not persisted at match level:
|
||||||
|
|
||||||
|
- raw full CRCON JSON payload
|
||||||
|
- derived win/loss per player
|
||||||
|
- any tactical event ledger
|
||||||
|
|
||||||
|
### Player identity level
|
||||||
|
|
||||||
|
Persisted per player:
|
||||||
|
|
||||||
|
- stable player key
|
||||||
|
- display name
|
||||||
|
- SteamID when available
|
||||||
|
- source player id
|
||||||
|
- first seen / last seen
|
||||||
|
|
||||||
|
### Player per match level
|
||||||
|
|
||||||
|
Persisted per player-match row:
|
||||||
|
|
||||||
|
- level
|
||||||
|
- team side
|
||||||
|
- kills
|
||||||
|
- deaths
|
||||||
|
- teamkills
|
||||||
|
- time seconds
|
||||||
|
- kills per minute
|
||||||
|
- deaths per minute
|
||||||
|
- kill/death ratio
|
||||||
|
- combat
|
||||||
|
- offense
|
||||||
|
- defense
|
||||||
|
- support
|
||||||
|
|
||||||
|
## What Exists In CRCON Source But Is Not Persisted
|
||||||
|
|
||||||
|
The documented CRCON detail payload already exposes fields that the project does
|
||||||
|
not currently store:
|
||||||
|
|
||||||
|
- `kills_by_type`
|
||||||
|
- `kills_streak`
|
||||||
|
- `longest_life_secs`
|
||||||
|
- `shortest_life_secs`
|
||||||
|
- `most_killed`
|
||||||
|
- `death_by`
|
||||||
|
- `weapons`
|
||||||
|
- `death_by_weapons`
|
||||||
|
|
||||||
|
These fields are visible in the source discovery, but the current upsert logic
|
||||||
|
only persists the smaller normalized subset listed above.
|
||||||
|
|
||||||
|
## What Was Not Confirmed As Available
|
||||||
|
|
||||||
|
The current repository evidence does not confirm any stable source fields for:
|
||||||
|
|
||||||
|
- garrisons destroyed
|
||||||
|
- outposts destroyed
|
||||||
|
- direct duel history in a structured reusable form
|
||||||
|
- tactical actions such as node building, dismantling or commander abilities
|
||||||
|
|
||||||
|
For direct encounters, the source does expose `most_killed` and `death_by`, but
|
||||||
|
that is not the same thing as a complete duel graph and is not stored today.
|
||||||
|
|
||||||
|
## Availability And Reliability Matrix
|
||||||
|
|
||||||
|
| Metric / signal | Exists in source | Persisted today | Reliability for ranking | Extra work | V1? |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| Kills | Yes | Yes | High | None | Yes |
|
||||||
|
| Deaths | Yes | Yes | High | None | Yes |
|
||||||
|
| Support | Yes | Yes | High | None | Yes |
|
||||||
|
| Combat | Yes | Yes | Medium-High | Query only | Maybe |
|
||||||
|
| Offense | Yes | Yes | Medium-High | Query only | Maybe |
|
||||||
|
| Defense | Yes | Yes | Medium-High | Query only | Maybe |
|
||||||
|
| Teamkills | Yes | Yes | High as penalty signal | Query only | Maybe |
|
||||||
|
| Match count | Yes | Derivable | High | Query only | Yes |
|
||||||
|
| Time played | Yes | Yes | High | Query only | Yes |
|
||||||
|
| KPM | Yes | Yes | Medium-High if computed from totals, lower if averaging raw per-match KPM | Query only | Yes |
|
||||||
|
| KDA / KD ratio | Yes | Yes | Medium-High if computed from totals, lower if averaging raw per-match KDA | Query only | Yes |
|
||||||
|
| 100+ kill matches | Derivable | Exposed in leaderboard | Medium | None | No |
|
||||||
|
| Win/loss context | Partially | Derivable from team side + scores when scores exist | Medium | Query and validation | Maybe |
|
||||||
|
| Weapons profile | Yes | No | Medium-Low for V1 | New persistence/modeling | No |
|
||||||
|
| Kill streak / life metrics | Yes | No | Medium-Low for V1 | New persistence/modeling | No |
|
||||||
|
| Direct encounters / duels | Partial only | No | Low today | New extraction plus modeling | No |
|
||||||
|
| Garrisons destroyed | Not confirmed | No | Unknown | Source validation first | No |
|
||||||
|
| OPs destroyed | Not confirmed | No | Unknown | Source validation first | No |
|
||||||
|
| Tactical impact composite | Partial proxies only | Partial | Medium after design work | Query/design | No for strict V1 |
|
||||||
|
|
||||||
|
## Current Product Readiness
|
||||||
|
|
||||||
|
The backend is already able to expose monthly leaderboard snapshots, but only
|
||||||
|
for these metrics:
|
||||||
|
|
||||||
|
- `kills`
|
||||||
|
- `deaths`
|
||||||
|
- `support`
|
||||||
|
- `matches_over_100_kills`
|
||||||
|
|
||||||
|
This means:
|
||||||
|
|
||||||
|
- the project already supports a monthly ranking surface operationally
|
||||||
|
- the current ranking surface is narrower than the real data persisted in SQLite
|
||||||
|
- offense, defense, combat, KPM and KDA are available in the database but not
|
||||||
|
yet wired as first-class monthly leaderboard metrics
|
||||||
|
|
||||||
|
## Recommendation For Ranking V1
|
||||||
|
|
||||||
|
A realistic V1 should use only metrics already persisted with strong coverage
|
||||||
|
and low modeling risk:
|
||||||
|
|
||||||
|
- total kills
|
||||||
|
- total support
|
||||||
|
- KPM recomputed from `SUM(kills) / SUM(time_seconds)`
|
||||||
|
- KDA recomputed from `SUM(kills) / NULLIF(SUM(deaths), 0)`
|
||||||
|
- minimum participation gate based on matches played and/or minutes played
|
||||||
|
- optional small penalty for teamkills
|
||||||
|
|
||||||
|
Why this is the safest V1:
|
||||||
|
|
||||||
|
- no new ingestion is required
|
||||||
|
- all needed raw fields already exist locally
|
||||||
|
- the ranking can avoid inflated outliers by requiring minimum activity
|
||||||
|
- KPM and KDA become more defensible when derived from totals, not from average
|
||||||
|
of precomputed per-match ratios
|
||||||
|
|
||||||
|
## Recommendation For Ranking V2
|
||||||
|
|
||||||
|
A stronger V2 can expand the model with already persisted but not yet surfaced
|
||||||
|
signals:
|
||||||
|
|
||||||
|
- offense
|
||||||
|
- defense
|
||||||
|
- combat
|
||||||
|
- win/loss context derived from player side and match result when scores exist
|
||||||
|
|
||||||
|
V2 may also evaluate source-only fields if a later task decides to persist them:
|
||||||
|
|
||||||
|
- weapons-based detail
|
||||||
|
- kill streak and life-span signals
|
||||||
|
- partial rivalry/encounter signals from `most_killed` and `death_by`
|
||||||
|
|
||||||
|
## Metrics Not Recommended For Early Use
|
||||||
|
|
||||||
|
Not recommended for V1 and not yet defensible for a serious monthly ranking:
|
||||||
|
|
||||||
|
- garrisons destroyed
|
||||||
|
- OPs destroyed
|
||||||
|
- duel ranking
|
||||||
|
- generic "impact in match" as a single opaque score
|
||||||
|
|
||||||
|
Reason:
|
||||||
|
|
||||||
|
- either the source availability is not confirmed
|
||||||
|
- or the source exists but the project does not yet persist enough structure to
|
||||||
|
make the metric auditable and stable
|
||||||
|
|
||||||
|
## Final Conclusion
|
||||||
|
|
||||||
|
The repository already has enough persisted historical data for a credible
|
||||||
|
monthly Top 3 V1 without touching ingestion:
|
||||||
|
|
||||||
|
- kills
|
||||||
|
- support
|
||||||
|
- time played
|
||||||
|
- deaths
|
||||||
|
- teamkills
|
||||||
|
- offense
|
||||||
|
- defense
|
||||||
|
- combat
|
||||||
|
|
||||||
|
The most realistic first release is a constrained monthly ranking based on
|
||||||
|
volume plus efficiency, using only persisted fields and explicit participation
|
||||||
|
thresholds. Tactical metrics such as garrisons, OPs and real duel graphs should
|
||||||
|
stay out of scope until the source is revalidated and the missing structures are
|
||||||
|
persisted deliberately.
|
||||||
Reference in New Issue
Block a user