feat(estimator): exclude city-centroid listings from radius analogs (Refs #769 Part E) #811
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#811
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/769-e-geo-centroid"
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?
Что
Последняя часть #769 (A1/A2/B/C/D — в #798/#804). Finding #17: bare-city адреса («Екатеринбург (Cian/N1)» без дома) геокодились в city-центроид и сохранялись как точные lat/lon → mislocated листинги участвовали в radius
ST_DWithin-аналогах, загрязняя comp set оценки.Как
ALTER TABLE listings ADD COLUMN IF NOT EXISTS geo_precision text(idempotent, BEGIN/COMMIT; backfill существующих city-coords — ops follow-up).ScrapedLot.geo_precision+ проброс вsave_listings.geocode_missing.py:geo_precision='city'через существующий_geocode_is_coarse(детерминированно: confidence=locality / нет house-number вfull_address).estimator._fetch_analogsTier H + Tier W:+ AND (geo_precision IS DISTINCT FROM 'city').Консервативность (важно — client-input-adjacent)
IS DISTINCT FROM 'city'→ строки сgeo_precision IS NULLпроходят. Т.е. до backfill существующие листинги (NULL) продолжают участвовать → сдвига оценок на merge нет; исключаются только новые/перегеокоженные city-centroid'ы. Тронут только WHERE-фильтр radius (2 строки) — pricing/anchor/median НЕ изменены.Тесты
tests/test_geo_precision.py(7): city-fallback→geo_precision='city'; radius-query содержит фильтр.pytest -k "geo or geocode or estimator or radius"→ 270 passed, ruff clean.Refs #769 (закрывает все 5 частей: A1/A2/B/C/D/E)
✅ APPROVE — #769 Part E, корректный консервативный фикс radius-comp-set.
Проверено:
_geocode_is_coarse(geo: GeocodeResult)существует (estimator.py:1322), сигнатура/логика точно совпадают с использованием вgeocode_missing.py(confidence=='locality' OR нет house-number токена → coarse). Импорт валиден.estimator.pyне импортируетapp.tasks/geocode_missing— связь однонаправленная._fetch_analogs(Tier H + Tier W, 2 строки).IS DISTINCT FROM 'city'пропускает NULL → сдвига оценок на merge нет (существующие листинги участвуют). Pricing/anchor/median/guard-bands НЕ изменены (#755 соблюдён).089идемпотентна (ADD COLUMN IF NOT EXISTS, BEGIN/COMMIT, после 088). ON CONFLICT не сбрасываетgeo_precisionна ре-скрейпе (сохраняется backfill-значение).Anti-regression: self-extending файлы не затронуты, секретов нет, SQL-фильтр — статический литерал (без injection).
Минор (не блокер): импорт приватной
_geocode_is_coarseчерез модульную границу — слегка inelegant, но дублирование coarse-логики хуже. ОК.Post-deploy: targeted backfill известных city-centroid адресов (
UPDATE listings SET geo_precision='city' WHERE address IN (...)) — ops follow-up по комменту в 089.