Avoid eager Elo/MMR imports during backend startup while the feature is paused. Add validation coverage for backend startup and health route resolution.
176 lines
8.0 KiB
Markdown
176 lines
8.0 KiB
Markdown
---
|
|
id: TASK-109
|
|
title: Keep backend startup independent from paused Elo/MMR
|
|
status: pending
|
|
type: backend
|
|
team: Backend Senior
|
|
supporting_teams: ["Arquitecto Python"]
|
|
roadmap_item: foundation
|
|
priority: high
|
|
---
|
|
|
|
# TASK-109 - Keep backend startup independent from paused Elo/MMR
|
|
|
|
## Goal
|
|
|
|
Fix backend startup so the default operational Compose profile can start `backend` and `frontend` while Elo/MMR and complex historical materialization remain paused.
|
|
|
|
The backend must expose `/health` and non-Elo routes even if Elo/MMR engine internals are unavailable or temporarily broken.
|
|
|
|
## Context
|
|
|
|
HLL Vietnam has simplified its default operational mode. The normal Compose profile should start only `backend` and `frontend`; historical workers, Elo/MMR, complex historical materialization, and server #03 are paused operationally.
|
|
|
|
Current validation shows:
|
|
|
|
- `docker compose config --services` returns only `backend` and `frontend`.
|
|
- `docker compose up -d --build` starts the frontend successfully.
|
|
- The frontend responds with HTTP 200.
|
|
- The backend restarts continuously.
|
|
- `/health` fails because backend startup imports Elo/MMR code.
|
|
- Backend logs include: `ImportError: cannot import name 'ELO_K_FACTOR' from 'app.elo_mmr_models'`.
|
|
- The startup import path is: `app.main -> app.routes -> app.payloads -> app.elo_mmr_engine -> app.elo_mmr_models`.
|
|
- `payloads.py` imports Elo/MMR payload functions at module import time, so a paused or broken Elo implementation can break the whole backend, including `/health`.
|
|
|
|
This task is startup-focused. Preserve the existing HLL Vietnam product identity and repository discipline, and keep the fix narrow.
|
|
|
|
## Steps
|
|
|
|
1. Inspect the listed files before changing anything.
|
|
2. Confirm the backend startup import path and where Elo/MMR is imported at module load time.
|
|
3. Refactor only the startup boundary needed so `/health` and non-Elo routes do not depend on successful import of Elo/MMR engine internals.
|
|
4. Prefer lazy importing Elo/MMR functions only inside Elo-specific payload builders or routes.
|
|
5. If Elo/MMR is paused or unavailable, make Elo-specific endpoints return a controlled unavailable or fallback payload instead of crashing backend import.
|
|
6. Preserve the public API shape as much as possible.
|
|
7. Add or update tests if a backend test framework exists.
|
|
8. Update lightweight validation if needed so future startup import regressions are caught.
|
|
9. Document the paused Elo/MMR startup boundary if documentation needs adjustment.
|
|
10. Run the required validation before committing.
|
|
11. Move this task file to `ai/tasks/done/` only after validation is complete and the outcome is documented.
|
|
12. Stage only intended files, commit, and push the branch to origin.
|
|
|
|
## Files to Read First
|
|
|
|
- `backend/app/main.py`
|
|
- `backend/app/routes.py`
|
|
- `backend/app/payloads.py`
|
|
- `backend/app/elo_mmr_engine.py`
|
|
- `backend/app/elo_mmr_models.py`
|
|
- `backend/app/config.py`
|
|
- `backend/tests/` if present
|
|
- `docker-compose.yml`
|
|
- `scripts/run-integration-tests.ps1`
|
|
- `README.md`
|
|
- `docs/decisions.md`
|
|
|
|
## Expected Files to Modify
|
|
|
|
- likely `backend/app/payloads.py`
|
|
- possibly `backend/app/routes.py`
|
|
- possibly `backend/app/elo_mmr_engine.py`
|
|
- possibly `backend/app/elo_mmr_models.py` only if justified
|
|
- possibly tests under `backend/tests/`
|
|
- possibly `scripts/run-integration-tests.ps1`
|
|
- this task file moved from `ai/tasks/pending/` to `ai/tasks/done/`
|
|
|
|
If additional files become necessary, explain why in the task outcome and commit message.
|
|
|
|
## Expected Files Not to Modify
|
|
|
|
- `frontend/**`
|
|
- `docker-compose.yml`, unless validation proves a Compose-only issue also exists
|
|
- database migrations
|
|
- persisted data
|
|
- unrelated backend modules
|
|
- server #03 configuration
|
|
|
|
## Constraints
|
|
|
|
- Do not delete Elo/MMR code.
|
|
- Do not delete historical ingestion code.
|
|
- Do not remove database migrations or persisted data.
|
|
- Do not change frontend behavior.
|
|
- Do not reintroduce server #03.
|
|
- Keep the fix narrow and startup-focused.
|
|
- Do not implement a new Elo/MMR algorithm.
|
|
- Do not reintroduce `ELO_K_FACTOR` as a blind compatibility patch unless you prove it is the smallest safe fix and still prevents startup coupling.
|
|
- Keep `/health` available even if Elo/MMR import fails.
|
|
- Preserve existing public API shape as much as possible.
|
|
- Do not modify unrelated files.
|
|
- Do not leave completed work only in local; commit and push after validation.
|
|
|
|
## Validation
|
|
|
|
Before completing the task, run and document:
|
|
|
|
- `git status`
|
|
- `powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1`
|
|
- `docker compose down`
|
|
- `docker compose up -d --build`
|
|
- `docker compose ps`
|
|
- `docker compose logs --tail=100 backend`
|
|
- `Invoke-WebRequest http://localhost:8000/health | Select-Object -ExpandProperty Content`
|
|
- `Invoke-WebRequest http://localhost:8080 | Select-Object -ExpandProperty StatusCode`
|
|
|
|
Also confirm and document:
|
|
|
|
- backend is not restarting
|
|
- `/health` returns a valid payload
|
|
- frontend still returns 200
|
|
- no frontend files changed
|
|
- no database migrations or persisted data changed
|
|
- `backend/runtime/` is not created or committed
|
|
- `git diff --name-only` matches the expected scope
|
|
|
|
If integration tests are relevant and `scripts/run-integration-tests.ps1` exists, use it. If no backend test framework exists for this scope, document that explicitly in the outcome.
|
|
|
|
## Commit And Push Requirements
|
|
|
|
- Run all validation before committing.
|
|
- Run `git status`.
|
|
- Stage only intended files.
|
|
- Commit with a clear message, for example: `fix: keep backend startup independent from paused elo`.
|
|
- Push the branch to origin.
|
|
- Do not leave completed work only in local.
|
|
|
|
## Outcome
|
|
|
|
- Validation performed:
|
|
- `git status --short`
|
|
- `python -c "import sys; sys.path.insert(0, 'backend'); import app.main; from app.routes import resolve_get_payload; print(resolve_get_payload('/health'))"`
|
|
- `python -c "import sys; sys.path.insert(0, 'backend'); from app.routes import resolve_get_payload; print(resolve_get_payload('/api/historical/elo-mmr/leaderboard'))"`
|
|
- `powershell -ExecutionPolicy Bypass -File scripts/run-integration-tests.ps1`
|
|
- `docker compose down`
|
|
- `docker compose up -d --build`
|
|
- `docker compose ps`
|
|
- `docker compose logs --tail=100 backend`
|
|
- `Invoke-WebRequest http://localhost:8000/health | Select-Object -ExpandProperty Content`
|
|
- `Invoke-WebRequest http://localhost:8080 | Select-Object -ExpandProperty StatusCode`
|
|
- `Invoke-WebRequest 'http://localhost:8000/api/historical/elo-mmr/leaderboard' | Select-Object -ExpandProperty Content`
|
|
- `git diff --name-only`
|
|
- Startup coupling removed:
|
|
- `backend/app/payloads.py` no longer imports `app.elo_mmr_engine` at module load time.
|
|
- Elo/MMR engine imports now happen only inside Elo/MMR payload builders.
|
|
- `app.main -> app.routes -> app.payloads` can load and serve `/health` without importing paused Elo/MMR internals.
|
|
- Elo/MMR unavailable behavior:
|
|
- If the Elo/MMR engine cannot be imported, Elo/MMR endpoints return the existing `status` + `data` envelope with `source: "elo-mmr-paused"`, `available: false`, `unavailable_reason: "elo-mmr-engine-import-unavailable"`, normal source policy metadata, and empty/null Elo data.
|
|
- Tests and validation:
|
|
- No backend test framework is configured for this scope.
|
|
- `scripts/run-integration-tests.ps1` now includes a lightweight backend startup import check and `/health` route resolution check.
|
|
- Scope confirmation:
|
|
- Backend was up and not restarting in `docker compose ps`.
|
|
- `/health` returned a valid JSON payload with `status: "ok"`.
|
|
- Frontend returned HTTP `200`.
|
|
- No frontend files changed.
|
|
- No database migrations, persisted data, or server #03 configuration changed.
|
|
- `backend/runtime/` was not created.
|
|
- `git diff --name-only` matched the expected scope: `backend/app/payloads.py` and `scripts/run-integration-tests.ps1`.
|
|
- Commit and push:
|
|
- Commit hash and pushed branch are recorded in the final task execution response.
|
|
|
|
## Change Budget
|
|
|
|
- Prefer fewer than 5 modified files.
|
|
- Prefer changes under 200 lines when feasible.
|
|
- Split follow-up work into a new task if the scope expands beyond startup independence.
|