fix(tradein/scrapers): bump scraped_at при ре-подтверждении живым + бэкфилл (#2206) #2224

Merged
lekss361 merged 1 commit from fix/tradein-scraped-at-upsert into main 2026-07-02 20:30:02 +00:00
Owner

Summary

  • Upsert ре-подтверждал листинг живым (last_seen_at=NOW(), обновлял цену/поля), но scraped_at не трогал никогда → эстиматор (фильтр scraped_at > NOW()-14d, estimator.py:3624/3665/3878/4276) видел лишь ~45.6% активного инвентаря (CIAN 934/15759 = 5.9%).
  • scraped_at = NOW() добавлен в ON CONFLICT DO UPDATE + dedup-drift reconcile UPDATE в обоих зеркальных base.py (app + scraper-kit; kit — боевой путь USE_KIT_SCHEDULER=true). Golden-parity тест держится (kit ≡ app байт-идентично).
  • Миграция 161_backfill_scraped_at_active_recent.sql: ретро scraped_at = last_seen_at для is_active avito/cian/yandex (~6.4k строк, идемпотентно by construction). domklik исключён намеренно — его last_seen_at испорчен нетрекаемым ежедневным bulk-touch (см. #2204), бэкфилл ложно освежил бы нескрейпленные строки.
  • Возвращаемый инвентарь несёт свежие цены: price_rub = EXCLUDED.price_rub обновляется тем же upsert'ом (verified в ревью).
  • 13 regression-тестов (оба пути × оба модуля + свойства миграции).

Эстиматорный контекст (backtest)

Живой baseline снят ДО изменения (engine=full, sample=300, --resolve-house-id, 2026-07-02): median_bias −2.73%, MAPE 14.7%, range-coverage 81.5%, sharpness 0.743, n=276/300. Изменение НЕ трогает pricing-логику — оно возвращает эстиматору подтверждённо-живой инвентарь со свежими ценами (данные, не веса). Замороженный CI-регресс-гейт (fixture replay) не зависит от прод-данных и остаётся зелёным. План: после deploy+backfill повторный live-бэктест тем же протоколом, сравнение в #2206 (ожидаемо: рост n_analogs, метрики не хуже; при деградации — revert-решение).

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

  • Полный локальный pytest: 2972 passed, 6 skipped, 1 deselected.
  • ruff — чисто. code-reviewer: APPROVE (minor: scraped_at IS NULL edge = no-op, задокументирован).
  • Post-deploy план: SELECT доли estimator-visible по источникам (CIAN сильно выше 5.9%).

Refs #2206

## Summary - Upsert ре-подтверждал листинг живым (`last_seen_at=NOW()`, обновлял цену/поля), но `scraped_at` не трогал никогда → эстиматор (фильтр `scraped_at > NOW()-14d`, estimator.py:3624/3665/3878/4276) видел лишь ~45.6% активного инвентаря (CIAN 934/15759 = 5.9%). - `scraped_at = NOW()` добавлен в ON CONFLICT DO UPDATE + dedup-drift reconcile UPDATE в **обоих** зеркальных base.py (app + scraper-kit; kit — боевой путь `USE_KIT_SCHEDULER=true`). Golden-parity тест держится (kit ≡ app байт-идентично). - Миграция `161_backfill_scraped_at_active_recent.sql`: ретро `scraped_at = last_seen_at` для is_active avito/cian/yandex (~6.4k строк, идемпотентно by construction). **domklik исключён намеренно** — его last_seen_at испорчен нетрекаемым ежедневным bulk-touch (см. #2204), бэкфилл ложно освежил бы нескрейпленные строки. - Возвращаемый инвентарь несёт свежие цены: `price_rub = EXCLUDED.price_rub` обновляется тем же upsert'ом (verified в ревью). - 13 regression-тестов (оба пути × оба модуля + свойства миграции). ## Эстиматорный контекст (backtest) Живой baseline снят ДО изменения (engine=full, sample=300, --resolve-house-id, 2026-07-02): median_bias **−2.73%**, MAPE **14.7%**, range-coverage **81.5%**, sharpness 0.743, n=276/300. Изменение НЕ трогает pricing-логику — оно возвращает эстиматору подтверждённо-живой инвентарь со свежими ценами (данные, не веса). Замороженный CI-регресс-гейт (fixture replay) не зависит от прод-данных и остаётся зелёным. План: после deploy+backfill повторный live-бэктест тем же протоколом, сравнение в #2206 (ожидаемо: рост n_analogs, метрики не хуже; при деградации — revert-решение). ## Как проверено - Полный локальный pytest: **2972 passed, 6 skipped, 1 deselected**. - ruff — чисто. code-reviewer: ✅ APPROVE (minor: `scraped_at IS NULL` edge = no-op, задокументирован). - Post-deploy план: SELECT доли estimator-visible по источникам (CIAN сильно выше 5.9%). Refs #2206
lekss361 added 1 commit 2026-07-02 20:21:24 +00:00
fix(tradein/scrapers): bump scraped_at on live re-confirm + backfill (#2206)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / changes (pull_request) Successful in 7s
CI Trade-In / backend-tests (pull_request) Successful in 1m38s
f7101aef3f
Upsert ре-подтверждал листинг живым (last_seen_at=NOW, обновлял цену/поля),
но scraped_at не трогал никогда. Эстиматор фильтрует свежесть по
scraped_at > NOW()-14d → видел лишь ~45.6% активного инвентаря (CIAN 5.9%).

- scraped_at=NOW() в ON CONFLICT DO UPDATE + dedup-drift reconcile UPDATE,
  в обоих зеркальных base.py (app + scraper-kit, kit — боевой путь)
- 161_backfill_scraped_at_active_recent.sql: ретро scraped_at=last_seen_at
  для active avito/cian/yandex (domklik исключён — испорченный bulk-touch
  last_seen_at ложно освежил бы нескрейпленные строки)
- regression-тесты: оба пути × оба модуля + свойства миграции 161

Refs #2206
lekss361 merged commit 47f45fc3d2 into main 2026-07-02 20:30:02 +00:00
lekss361 deleted branch fix/tradein-scraped-at-upsert 2026-07-02 20:30:02 +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#2224
No description provided.