8.4 KiB
id, title, status, type, team, supporting_teams, roadmap_item, priority
| id | title | status | type | team | supporting_teams | roadmap_item | priority | ||
|---|---|---|---|---|---|---|---|---|---|
| TASK-202-isolate-runner-read-model-refresh-from-legacy-snapshot-failures | Isolate runner read model refresh from legacy snapshot failures | done | backend | Backend Senior |
|
foundation | high |
TASK-202 - Isolate runner read model refresh from legacy snapshot failures
Goal
Prevent legacy historical snapshot failures from blocking the operational PostgreSQL read-model refreshes in the periodic historical runner.
Context
After TASK-201, the periodic runner starts correctly and announces the expected hourly scope, but the first cycle aborts before reaching the PostgreSQL operational read models when legacy historical snapshot generation fails with sqlite3.OperationalError: no such table: player_event_raw_ledger.
The current failure path happens inside generate_historical_snapshots(...), which was still executed inside the runner's broader refresh attempt. That legacy failure prevented the cycle from refreshing:
player_search_indexplayer_period_statsranking_snapshots
This task isolates the cycle steps so the legacy error stays visible in logs and results, while the operational PostgreSQL refreshes are still attempted in the same cycle. Preserve the current product identity: Spanish-speaking HLL Vietnam community, military/Vietnam/tactical/sober visual direction and controlled repository evolution.
Steps
- Read the listed files first.
- Confirm the current runner failure path and where legacy snapshot generation aborts the cycle.
- Refactor the periodic runner so each refresh step is handled as an isolated unit with a separately reported result.
- Preserve retries for full-attempt failures where they still apply, but avoid retry-only behavior for a legacy step that should no longer block operational refreshes.
- Keep the legacy snapshot error visible in logs and cycle results.
- Ensure the runner still attempts:
refresh_player_search_index(...)refresh_player_period_stats(...)refresh_ranking_snapshots(...)even whengenerate_historical_snapshots(...)fails.
- Return a global cycle status of
partialor equivalent when the legacy snapshot step fails but operational steps continue. - Keep manual CLIs and public API contracts unchanged.
- Update operational documentation with the new partial-cycle behavior and production validation guidance.
Files to Read First
AGENTS.mdai/repo-context.mdai/architecture-index.mdbackend/app/historical_runner.pybackend/app/historical_snapshots.pybackend/app/historical_storage.pybackend/app/rcon_historical_player_stats.pybackend/app/rcon_historical_leaderboards.pyscripts/run-stats-validation.ps1docs/player-search-read-model-plan.mddocs/player-period-stats-read-model-plan.mddocs/ranking-snapshot-read-model-plan.mdai/tasks/done/TASK-201-automate-player-read-model-refresh.md
Expected Files to Modify
backend/app/historical_runner.pybackend/tests/test_historical_snapshot_refresh.pyscripts/run-stats-validation.ps1docs/player-search-read-model-plan.mddocs/player-period-stats-read-model-plan.mddocs/ranking-snapshot-read-model-plan.mdai/tasks/done/TASK-202-isolate-runner-read-model-refresh-from-legacy-snapshot-failures.md
Constraints
- Keep the change minimal and backend/documentation only.
- Do not execute
ai-platform run. - Do not modify frontend.
- Do not change design.
- Do not touch images or assets.
- Do not reactivate Elo/MMR.
- Do not reintroduce Comunidad Hispana
#03. - Do not fix or migrate
player_event_raw_ledgerin this task unless analysis proves it is strictly necessary. - Do not create or modify legacy tables unless it becomes strictly necessary and is explicitly justified in the outcome.
- Do not hide legacy errors; they must remain visible in logs and result payloads.
- Do not change manual CLI behavior.
- Do not change public API contracts.
Validation
Before completing the task ensure:
python -m py_compile backend/app/historical_runner.pypowershell -ExecutionPolicy Bypass -File scripts/run-stats-validation.ps1powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1- local/import validation proves that when
generate_historical_snapshots(...)fails:refresh_player_search_index(...)is still attemptedrefresh_player_period_stats(...)is still attemptedrefresh_ranking_snapshots(...)is still attempted- the global result is
partialor equivalent - the legacy error remains reported
- local/import validation proves that when all steps succeed, the cycle still returns
ok - local/import validation proves separate result payloads still exist:
historical_snapshot_resultplayer_search_index_resultplayer_period_stats_resultranking_snapshot_result
git diff --name-onlymatches the expected scope
Outcome
Root cause:
generate_historical_snapshots(...)still ran inside the runner attempt's broad failure boundary.- When the legacy monthly MVP V2 snapshot path touched missing
player_event_raw_ledgerstate, it raisedOperationalError. - That exception aborted the attempt before the PostgreSQL operational read-model refreshes were called.
Previous behavior:
- a legacy snapshot failure stopped the cycle before:
player_search_indexplayer_period_statsranking_snapshots
- the cycle returned attempt-level failure instead of a partial operational result
- operators could see the legacy error, but the operational read models stayed stale
New behavior:
backend/app/historical_runner.py- wraps legacy snapshot refresh in an isolated step via
refresh_periodic_historical_snapshots(...) - preserves the legacy error in logs and result payloads with:
historical_snapshot_result- compatibility alias
snapshot_result - event
historical-snapshot-refresh-failed
- continues attempting:
player_search_indexplayer_period_statsranking_snapshotsafter a legacy snapshot failure
- resolves the overall cycle to
partialwhen the isolated legacy step fails but operational refreshes continue
- wraps legacy snapshot refresh in an isolated step via
backend/tests/test_historical_snapshot_refresh.py- adds coverage for legacy snapshot failure isolation
- adds coverage for the all-success path still returning
ok
scripts/run-stats-validation.ps1- validates that a legacy snapshot failure still leaves the operational read-model refresh sequence running
- validates:
historical_snapshot_resultplayer_search_index_resultplayer_period_stats_resultranking_snapshot_result
- validates the global
partialresult and preserved legacy error reporting
- operational docs now explain that the runner can finish
partialif the legacy block fails while PostgreSQL read-model refreshes still run
Validations executed:
python -m py_compile backend/app/historical_runner.pypython -m unittest tests.test_historical_snapshot_refreshpowershell -ExecutionPolicy Bypass -File scripts/run-stats-validation.ps1powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1
Production validation:
- Run one controlled cycle:
python -m app.historical_runner --max-runs 1
- Inspect the cycle payload and logs for:
statusequal tookorpartialhistorical_snapshot_resultplayer_search_index_resultplayer_period_stats_resultranking_snapshot_result
- If
status=partial, confirm the legacy failure remains visible under:historical_snapshot_result.error_typehistorical_snapshot_result.errorhistorical_snapshot_result.traceback
- Confirm operational timestamps still advance in PostgreSQL for:
player_search_indexplayer_period_statsranking_snapshots
- Confirm public reads still use the refreshed read models:
/api/stats/players/search/api/stats/players/{player_id}/api/ranking
Scope notes:
- no frontend files were modified
- no images/assets were touched
player_event_raw_ledgerwas not fixed or migrated in this task- manual CLIs were preserved unchanged
- pre-existing unrelated changes in
ai/system-metrics.mdand frontend assets were intentionally left untouched
Change Budget
- Prefer fewer than 5 modified files.
- Prefer changes under 200 lines when feasible.
- Split the work into follow-up tasks if limits are exceeded.