MLflow Registry Audit Report — SoccerPredictAI¶
Date: 2026-04-24
Auditor: GitHub Copilot (Claude Sonnet 4.6)
Scope: MLflow experiments, runs, lineage, Model Registry, aliases, naming
Method: анализ src/utils/mlflow_meta.py, src/models/classification.py, src/models/final_train.py, src/pipelines/register_model.py, params.yaml, mlruns/
1. Experiments Structure¶
1.1 Инвентаризация экспериментов¶
По коду (mlflow_meta.py docstring):
| Experiment name | Назначение | Активен |
|---|---|---|
matches_clf |
production runs: train_eval, ablation, tuning, final_train | ✅ (planned convention) |
matches_clf_smoke |
smoke / fast-dev runs | ✅ (текущий активный) |
Текущий конфиг: params.yaml: classification.experiment_name = matches_clf_smoke — все runs пишутся в smoke эксперимент.
⚠️ P1: Весь production pipeline записывает в matches_clf_smoke, а не в matches_clf. Нет автоматического переключения между smoke и production экспериментами.
1.2 Naming conventions¶
Experiments:
- matches_clf / matches_clf_smoke — единообразное именование ✅
Runs:
| Тип run | Формат имени | Пример |
|---------|-------------|--------|
| Parent (train_eval) | [smoke \| ]train_eval \| frac={frac} \| feat={profile} | train_eval \| frac=0.001 \| feat=full |
| Parent (ablation) | [smoke \| ]ablation \| variant={v} \| frac={frac} | ablation \| variant=elo_only \| frac=0.001 |
| Child (model) | model \| {model_name} | model \| xgb |
| XGB tuning parent | xgb_tuning_frac-{frac} | xgb_tuning_frac-0.1 |
| Final train | [smoke \| ]final_train \| model={name} | final_train \| model=xgb |
✅ Именование консистентно.
Tags:
| Tag | Значение | Логируется |
|-----|----------|-----------|
| pipeline.run_kind | smoke/train_eval/final_train | ✅ |
| pipeline.stage | train_eval/ablation/final_train | ✅ |
| pipeline.scope | parent/child | ✅ |
| pipeline.variant | baseline/elo_only/etc | ✅ |
| features.profile | full/elo_only/stats_only/no_h2h | ✅ |
| model.family | gradient_boosting/linear/dummy | ✅ |
| data.version | ETag из .minio.json | ✅ |
| data.source_last_modified | MinIO LastModified | ✅ |
| data.ingested_at | ingested_at из .minio.json | ✅ |
| pipeline.git_sha | HEAD SHA | ✅ |
| pipeline.params_hash | SHA256 params.yaml | ✅ |
2. Run Lineage¶
2.1 Parent / child runs¶
Структура:
Parent run: train_eval | frac=... | feat=...
└── Child: model | baseline
└── Child: model | logreg
└── Child: model | sgd_logloss
└── Child: model | hgb
└── Child: model | xgb
✅ Nested runs используются корректно.
2.2 Data lineage¶
В каждом run логируются:
| Поле | Ожидается | Логируется |
|---|---|---|
| data.version (ETag) | ✅ | ✅ build_data_lineage_tags() |
| data.source_last_modified | ✅ | ✅ |
| data.ingested_at | ✅ | ✅ |
| data.train_rows | ✅ | ✅ |
| data.test_rows | ✅ | ✅ |
| data.train_start / train_end | ✅ | ✅ |
| data.test_start | ✅ | ✅ |
| pipeline.git_sha | ✅ | ✅ |
| pipeline.params_hash | ✅ | ✅ |
| pipeline.dvc_exp_name | ✅ | ✅ (из env DVC_EXP_NAME) |
| dataset logged as MLflow input | ✅ | ✅ mlflow.log_input() |
⚠️ P2: data.source_created_at явно не логируется (задокументировано в docstring — MinIO не предоставляет creation time отдельно от last_modified).
3. Model Registry¶
3.1 Структура Registry¶
| Параметр | Значение |
|---|---|
| Model name | soccer_clf |
| Stage/Alias | champion |
| Registration стадия | register_model DVC stage |
| Тригер | зависит от final_train → final_run_id.json |
3.2 Registration logic (register_model.py)¶
# Идемпотентность: если alias уже указывает на run_id — skip
# Иначе: create version → set alias "champion"
✅ Idempotency реализована — повторный запуск с тем же run_id безопасен.
3.3 Champion/Challenger¶
| Аспект | Статус |
|---|---|
Champion alias (champion) |
✅ |
| Challenger pattern | ❌ не реализован |
| Автоматическое A/B или shadow deployment | ❌ не реализован |
| Ручная gate перед promotion | 🚧 Требует ручного шага (status.md) |
⚠️ P1: Нет champion/challenger сравнения — каждый final_train автоматически становится champion без сравнения с предыдущей моделью.
4. Registry → Serving Connection¶
# src/app/tasks/predict.py
_service = PredictionService(
tracking_uri=settings.mlflow.tracking_uri,
model_name=settings.mlflow.model_name, # = "soccer_clf"
model_stage=settings.mlflow.model_stage, # = "champion"
)
✅ Serving загружает модель по alias champion — правильная связь registry → serving.
⚠️ P1: Нет graceful rollback механизма — если новый champion деградирует, нет автоматического revert.
5. Artifacts в MLflow¶
| Артефакт | Логируется |
|---|---|
| sklearn model (mlflow.sklearn) | ✅ |
| confusion matrix plots | ✅ plot_confusion_matrix_multiclass() |
| calibration curves | ✅ plot_calibration_curves() |
| feature importance plots | ✅ plot_feature_importance() |
| folds.csv | ✅ |
| predictions / holdout CSV | ✅ (в final_train) |
| segment metrics | ✅ |
| ECE (raw + calibrated) | ✅ |
6. Findings¶
| ID | Severity | Описание |
|---|---|---|
| ML-01 | P1 | Все runs пишутся в matches_clf_smoke — нет переключения на production experiment при production-запуске |
| ML-02 | P1 | Нет champion/challenger сравнения при регистрации — новая модель автоматически становится champion |
| ML-03 | P1 | Нет автоматического rollback при деградации модели после promotion |
| ML-04 | P2 | ablation_study runs пишутся в тот же эксперимент что и train_eval — нет явного разделения exploratory vs training runs |
| ML-05 | P2 | pipeline.dvc_exp_name берётся из env DVC_EXP_NAME — при запуске вне DVC env этот тег будет отсутствовать |