fix(tradein/geocode): передавать город объявления как city_hint в геокодирование (#2594) #2601
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#2601
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/tradein-geocode-city-hint"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что сделано
Замыкает петлю "город объявления -> геокодирование" (issue #2594, шаг 2/3). Колонка
listings.city(миграция 196, PR #2598) уже заполняется скрапером из контекста развёртки, но три caller-места геокодера решали город по ТЕКСТУ адреса и игнорировали колонку — голый адрес без города в тексте ("ул. Победы, 30", тагильский) уходил в Екатеринбург.geocoder.py::geocode(address, db, city_hint=None)УЖЕ умеет принимать и корректно обрабатыватьcity_hint— он НЕ тронут (см. ниже).1.
app/tasks/geocode_missing.py(address, city)вместо толькоaddress— один и тот же текст адреса в разных городах теперь две разные группы с раздельными geocode-вызовами.geocode(address, db, city_hint=city).WHERE address = :addr AND city IS NOT DISTINCT FROM :city AND lat IS NULL.cityв GROUP BY/ORDER BY/WHERE.2.
app/tasks/backfill_listings_coords_geoportal.pycityПЕРЕД матчем против EKB-onlyekb_geoportal_buildingsИ перед существующим текстовым гейтом_names_non_ekb_city: еслиcity IS NOT NULL AND city <> 'Екатеринбург'→ skip (считается в существующий счётчикskipped_non_ekb).city IS NULL(записаны до миграции 196 либо путём, не проставляющим город — admin ad-hoc/admin/scrape).geocode_missing_listingsв ночном расписании — без гейта по колонке оно успевало испортить координаты первым (проставить ЕКБ-координаты тагильскому дому с совпадающими street+house до того, какgeocode_missing_listingsвообще получал шанс).3.
app/api/v1/admin.py(POST /geocode-missing, per-ID endpoint)city(колонка есть в обеих целевых таблицах —listings.cityмиграция 196,deals.cityмиграция 177) и передаёт какcity_hintвgeocode().Почему
IS NOT DISTINCT FROM, а не=Стандартная SQL NULL-семантика:
city = NULLникогда неtrue— обычным=группа сcity IS NULLне обновилась бы вообще ни для одной строки.IS NOT DISTINCT FROMтрактуетNULL = NULLкак совпадение, оставаясь строгим при непустомcity— ровно нужная симметрия: NULL-город — отдельная группа, а не "любой город".geocoder.pyне тронутЗапрещено ТЗ (переработан дважды подряд, #2580/#2582/#2589). Подтверждение:
git diff forgejo/main -- tradein-mvp/backend/app/services/geocoder.py— пусто.Тесты (falsification-прогон)
На каждое из трёх мест — тест, падающий на старом коде и проходящий после правки. Ключевой сценарий (
geocode_missing): две записи с ОДИНАКОВЫМ текстом адреса и РАЗНЫМИ городами — каждая получает свои координаты, UPDATE одной не задевает другую.Процедура:
git stash pushтолько трёх implementation-файлов (тесты остались нетронутыми) → прогон →git stash pop→ повторный прогон.7 failed, 36 passed— все 7 фейлов это новые тесты на новое поведение (geocode_missing.py— 4,admin.py— 2,backfill_listings_coords_geoportal.py— 1).43 passed, 0 failed.Полный pytest (
tradein-mvp/backend)2970 passed, 1 failed, 9 skipped— единственный фейлtests/test_search_api.py::test_search_cache_hit(pre-existing 401 от RBAC-мидлвари, к задаче не относится, не чинил по инструкции).Refs #2594