feat(tradein/monitor): алерт на staleness данных deals по max(deal_date) (#2212) #2226

Merged
lekss361 merged 1 commit from fix/tradein-deals-freshness-monitor into main 2026-07-02 20:50:37 +00:00
Owner

Summary

  • Расследование (2026-07-02): импорт rosreestr_dkp НЕ сломан. deal_date = лейбл начала квартала; 2026Q1 — последний квартал, опубликованный Росреестром (исторические кварталы загружены разово 26.04; Q2 закончился 30.06, публикация ~август). done+inserted:0 = «всё уже импортировано», но этот статус маскирует будущий пропуск операторского импорта — ровно паттерн аудита «алерт на данные, не на статус».
  • Новый daily-монитор deals_freshness_monitor: смотрит max(deal_date), поднимает ERROR-лог → GlitchTip, когда следующий квартал просрочен (порог = конец имеющегося квартала + 3 мес + 45д лага публикации). Сейчас алерта нет (2026Q1 актуален); с 2026-08-16 при неимпортированном Q2 — алерт с actionable-сообщением (операторский шаг data/sql/02_load_all_quarters.sh).
  • Оба dispatch-пути: kit registry (боевой) + legacy scheduler. Seed-миграция 162 (daily, 08:00-09:00 UTC, идемпотентно).
  • Чистая функция evaluate_deals_freshness (frozen-now testable) — 23 теста: границы порога (15/16 августа), год-переход, month-clamp, пустая таблица → mark_failed, migration props, registry parity.

Как проверено

  • Полный локальный pytest: 2982 passed, 6 skipped, 1 deselected.
  • ruff — чисто. code-reviewer: APPROVE (арифметика порога и год-переход проверены отдельно; ссылка на операторский скрипт валидна).
  • Post-deploy: убедиться, что row deals_freshness_monitor в scrape_schedules; первый прогон ожидается done c counters {latest_quarter: 2026Q1, alert: 0}.

Оставшееся по #2212 (вне этого PR)

  • «Восстановить приток свежих ДКП» — внешняя зависимость: Росреестр публикует Q2 ~август; после публикации quarter_poll задетектит, импорт — операторский шаг (задокументирован в rosreestr_quarter_poll.py). Монитор теперь не даст этому пройти незамеченным.
  • Пересчёт asking-to-sold на свежих сделках — проверяется после реального импорта Q2 (job asking_to_sold_ratio_refresh уже в расписании после dkp_import).

Refs #2212

## Summary - **Расследование (2026-07-02):** импорт rosreestr_dkp НЕ сломан. `deal_date` = лейбл начала квартала; 2026Q1 — последний квартал, опубликованный Росреестром (исторические кварталы загружены разово 26.04; Q2 закончился 30.06, публикация ~август). `done`+`inserted:0` = «всё уже импортировано», но этот статус маскирует будущий пропуск операторского импорта — ровно паттерн аудита «алерт на данные, не на статус». - Новый daily-монитор `deals_freshness_monitor`: смотрит `max(deal_date)`, поднимает **ERROR-лог → GlitchTip**, когда следующий квартал просрочен (порог = конец имеющегося квартала + 3 мес + 45д лага публикации). Сейчас алерта нет (2026Q1 актуален); с 2026-08-16 при неимпортированном Q2 — алерт с actionable-сообщением (операторский шаг `data/sql/02_load_all_quarters.sh`). - Оба dispatch-пути: kit registry (боевой) + legacy scheduler. Seed-миграция 162 (daily, 08:00-09:00 UTC, идемпотентно). - Чистая функция `evaluate_deals_freshness` (frozen-now testable) — 23 теста: границы порога (15/16 августа), год-переход, month-clamp, пустая таблица → mark_failed, migration props, registry parity. ## Как проверено - Полный локальный pytest: **2982 passed, 6 skipped, 1 deselected**. - ruff — чисто. code-reviewer: ✅ APPROVE (арифметика порога и год-переход проверены отдельно; ссылка на операторский скрипт валидна). - Post-deploy: убедиться, что row `deals_freshness_monitor` в `scrape_schedules`; первый прогон ожидается `done` c counters `{latest_quarter: 2026Q1, alert: 0}`. ## Оставшееся по #2212 (вне этого PR) - «Восстановить приток свежих ДКП» — внешняя зависимость: Росреестр публикует Q2 ~август; после публикации quarter_poll задетектит, импорт — операторский шаг (задокументирован в rosreestr_quarter_poll.py). Монитор теперь не даст этому пройти незамеченным. - Пересчёт asking-to-sold на свежих сделках — проверяется после реального импорта Q2 (job `asking_to_sold_ratio_refresh` уже в расписании после dkp_import). Refs #2212
lekss361 added 1 commit 2026-07-02 20:32:01 +00:00
feat(tradein/monitor): алерт на staleness данных deals по max(deal_date) (#2212)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 1m36s
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
30d91be796
Джоба-статус rosreestr_* остаётся done при quarter-stale данных (inserted=0
== всё импортировано), маскируя пропущенный операторский импорт нового
квартала. Новый daily-монитор смотрит max(deal_date) и поднимает ERROR-алерт
(→ GlitchTip), когда следующий квартал просрочен публикацией
(порог = конец имеющегося квартала + 3 мес + 45д лага).

Расследование (2026-07-02): импорт НЕ сломан — deal_date = лейбл начала
квартала, 2026Q1 = последний опубликованный Росреестром (Q2 закончился
30.06, публикация ожидается ~август; исторические кварталы загружены
разово 26.04). Монитор ловит именно пропуск ОПЕРАТОРСКОГО шага
(data/sql/02_load_all_quarters.sh), когда quarter_poll задетектит Q2.

- app/tasks/deals_freshness_monitor.py — чистая evaluate_deals_freshness
  (frozen-now testable) + DB-обёртка; overdue → ERROR-лог, не failed
- scheduler.py + product_handlers.py — оба dispatch-пути (kit боевой + legacy)
- data/sql/162 — seed (daily, 08:00-09:00 UTC, lag_allowance_days=45)
- 23 теста: арифметика порога (год-переход, clamp), migration props, parity

Refs #2212
lekss361 merged commit ac19c4f7b3 into main 2026-07-02 20:50:37 +00:00
lekss361 deleted branch fix/tradein-deals-freshness-monitor 2026-07-02 20:50:38 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2226
No description provided.