fix(tradein): бэкфилл-чистка неверных oblast-меток city для yandex/cian (#2628) #2646

Merged
bot-backend merged 1 commit from fix/tradein-city-label-backfill into main 2026-08-05 07:13:29 +00:00
Collaborator

Summary

#2628: write-time гео-guard (#2626) не самозалечивает накопленные неверные городские метки (COALESCE в upsert не даёт NULL перетереть старое). Миграция 207 чистит их — строго по ограничениям issue:

  • Только yandex/cian — Авито не тронут: его SERP-координаты — ЕКБ-центроид геокодера при верном тексте адреса; наивный гео-критерий снёс бы ~640 корректных меток.
  • Двойной критерий: haversine 1:1 с write-time guard'ом (anchors/радиусы из CITY_ANCHORS, Пышма 8 км, остальные 15 км) И «адрес не называет город метки» (issue п.2) — покрывает оба известных false-positive (Орджоникидзе-1, Береговая-7А); направление ошибки безопасное (лишний ILIKE-match = не трогаем).
  • Только city = NULL (строки не удаляются); money-path (asking_to_sold_ratio) безопасен — NULL считается «своим», плюс он фильтрует is_active (проверено ревью).
  • Idempotent (повторный прогон = 0 строк), UPDATE-only, NN=207 без коллизий.

Прод dry-run (прогнан до PR, SELECT в шапке миграции): 53 строки — yandex/Верхняя Пышма 45, yandex/Первоуральск 8. Меньше issue-оценки ~115: применены оба критерия (у ~60 строк адрес называет свой город — им доверяем, тот же принцип, что защищает Авито) + часть листингов деактивировалась с 02.08.

Побочно (из issue): поправлены 6 комментариев, неверно объяснявших вектор утечки — «radius_m=25000» → реальный вектор rgid (city-scoped выдача Яндекса, radius_m инертен per providers/yandex/serp.py:655). Только формулировки, код не тронут (проверено ревью).

Test plan

  • Прод dry-run: 53 строки, разбивка по source/city выше
  • Полный tradein-сьют 3221 passed (1 known pre-existing 401); ruff чисто; 38 passed в затронутых тест-модулях
  • Post-deploy: повторный dry-run → 0 строк (применилось); SELECT count(*) FROM listings WHERE city IS NULL AND source IN ('yandex','cian') вырос на ~53

Review

code-reviewer: APPROVE — все 7 проверок (idempotency + механика _schema_migrations, безопасность WHERE, haversine-эквивалентность посимвольно, anchors 1:1 с источником вкл. Серов-долготу, адресный критерий, comment-only .py-правки, скоуп/NN).

Refs #2628

## Summary **#2628**: write-time гео-guard (#2626) не самозалечивает накопленные неверные городские метки (`COALESCE` в upsert не даёт NULL перетереть старое). Миграция `207` чистит их — **строго по ограничениям issue**: - **Только yandex/cian** — Авито не тронут: его SERP-координаты — ЕКБ-центроид геокодера при верном тексте адреса; наивный гео-критерий снёс бы ~640 корректных меток. - **Двойной критерий**: haversine 1:1 с write-time guard'ом (anchors/радиусы из `CITY_ANCHORS`, Пышма 8 км, остальные 15 км) **И** «адрес не называет город метки» (issue п.2) — покрывает оба известных false-positive (Орджоникидзе-1, Береговая-7А); направление ошибки безопасное (лишний ILIKE-match = не трогаем). - Только `city = NULL` (строки не удаляются); money-path (`asking_to_sold_ratio`) безопасен — NULL считается «своим», плюс он фильтрует `is_active` (проверено ревью). - Idempotent (повторный прогон = 0 строк), UPDATE-only, NN=207 без коллизий. **Прод dry-run (прогнан до PR, SELECT в шапке миграции): 53 строки** — yandex/Верхняя Пышма 45, yandex/Первоуральск 8. Меньше issue-оценки ~115: применены оба критерия (у ~60 строк адрес называет свой город — им доверяем, тот же принцип, что защищает Авито) + часть листингов деактивировалась с 02.08. Побочно (из issue): поправлены 6 комментариев, неверно объяснявших вектор утечки — «radius_m=25000» → реальный вектор `rgid` (city-scoped выдача Яндекса, radius_m инертен per `providers/yandex/serp.py:655`). Только формулировки, код не тронут (проверено ревью). ## Test plan - [x] Прод dry-run: 53 строки, разбивка по source/city выше - [x] Полный tradein-сьют 3221 passed (1 known pre-existing 401); ruff чисто; 38 passed в затронутых тест-модулях - [ ] Post-deploy: повторный dry-run → 0 строк (применилось); `SELECT count(*) FROM listings WHERE city IS NULL AND source IN ('yandex','cian')` вырос на ~53 ## Review code-reviewer: **✅ APPROVE** — все 7 проверок (idempotency + механика `_schema_migrations`, безопасность WHERE, haversine-эквивалентность посимвольно, anchors 1:1 с источником вкл. Серов-долготу, адресный критерий, comment-only .py-правки, скоуп/NN). Refs #2628
bot-backend added 1 commit 2026-08-05 07:04:51 +00:00
fix(tradein): бэкфилл-чистка неверных oblast-меток city для yandex/cian (#2628)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
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 Trade-In / backend-tests (pull_request) Successful in 2m44s
d1ec6d02ec
Write-time гео-guard (#2626) не самозалечивает накопленное: COALESCE в
upsert не даёт новому NULL перетереть старую неверную метку. Чистка строго
ограничена yandex/cian (провайдерские координаты правдивы) — Авито не
трогаем: его SERP-координаты — ЕКБ-центроид геокодера при верном тексте
адреса, наивный гео-критерий снёс бы ~640 корректных меток. Двойной
критерий (haversine 1:1 с guard'ом + «адрес не называет город метки»)
покрывает оба известных false-positive. Прод dry-run: 53 строки
(Пышма 45, Первоуральск 8). Idempotent, UPDATE-only.

Побочно: поправлены 6 комментариев, неверно объяснявших вектор утечки
(radius_m=25000 → реальный вектор rgid, city-scoped выдача Яндекса).

Refs #2628
bot-backend merged commit 2dd0f057f1 into main 2026-08-05 07:13:29 +00:00
bot-backend deleted branch fix/tradein-city-label-backfill 2026-08-05 07:13:29 +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#2646
No description provided.