МЕРА, область: коридор сделок узнаёт города развёрток, ГАР не раздаёт домам чужой регион, история цен не врёт про «только этот дом» #3575
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3575
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/region-audit-tail"
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?
Остаток аудита области #2583. Три независимые правки, по коммиту на каждую. #2583 этим PR не закрывается (что осталось — в конце).
Перед работой сверил статус пунктов по коду
mainи по проду:db4fb0a9вmain, Guard-5 на месте, тестtest_estimator_quarter_index.py).listings.city.H1: город развёртки попадает в городской фильтр коридора сделок
Что было.
_resolve_target_cityзнал 24 имени изREGIONS[66].cities, а развёртки идут ещё по 23 городам: Реж, Карпинск, Кушва, Лесной, Тавда, Ивдель, Туринск, Артёмовский, Камышлов и другие. Если город не распознан,_fetch_dkp_corridorсобирает сделки по одной улице во всей области. «Ленина» там в основном екатеринбургская, поэтому Реж получал коридор по ценам Екатеринбурга. От того же резолвера зависят/street-deals,/sales-vs-listingsи повторное открытие оценки: они тоже терялись.Улики (прод, 2026-09-17, только чтение).
dealsесть сделки Росреестра,cityзаписан в форме с «е»: Реж 745 (из них 189 за 12 мес.), Карпинск 521/161, Лесной 1215/402, Артемовский 562/185.city='Екатеринбург'ни в одном адресе эти имена не встречаются отдельным словом.trade_in_estimatesни одна пока не называет эти города, то есть вред ещё не случился.Что сделано. Резолвер теперь знает и города развёрток: имена из
CITY_DISPLAY_NAMES, те же, что пишутся вlistings.city. Города других регионов (Москву) исключаю. ОбщийREGIONS[66].citiesсознательно не трогал. На нём стоят гейты геокодера, которые в #2582 намеренно ушли от перечисления городов. Ещё на нём держатся токены ключа дома:_OBLAST_CITY_TOKENSвырезал бы «новая»/«лесной» из названий улиц.Не сделано. Населённый пункт вне обоих словарей (сёла) по-прежнему даёт коридор без города. За всю историю таких оценок 1 из 1275: вне bbox ЕКБ, внутри региона 66, город не распознан. Если понадобится, можно отключать коридор, когда город неизвестен и точка вне ЕКБ.
H5: дом получает ГАР-guid только своего региона
Что было. Фильтры матча (регион и город) стояли только на стороне ГАР.
UPDATE housesшёл по канону «улица+дом» по всем домам всех регионов. После #3523 (матч для 77 и 50) это стало порчей данных.Улики (прод, 2026-09-17). Соединил
houses.gar_house_guidсgar_house_flats.house_guid:По чужому guid загрузчики ФРТ и капремонта матчат
COALESCE(gar_house_guid, house_fias_id, …): чужой идентификатор важнее своего ФИАС.Что сделано.
houses.region_codeс регионом ГАР-строки. Канон ранжируется внутри региона:PARTITION BY region_code, canon.canon_addr-guid чужого региона. Без этого дом, у которого нет пары в своём регионе, так и остался бы с чужим guid. Дом безregion_codeне трогаю: не доказано, что guid чужой.Городская часть H5 внутри региона 66 не сделана, и это осознанно. Текстовый фильтр «адрес дома называет другой город» ложно исключил бы 17 правильных екатеринбургских домов с адресом «мкр. Заречный». Домов, которые называют другой город и при этом получили екатеринбургский guid, на проде 0. Около 13 домов с голым адресом вне bbox ЕКБ (Верхняя Пышма, Среднеуральск) текстом не отличить.
Уже записанные данные ФРТ и капремонта, пришедшие по чужому guid, эта правка не исправляет.
M2: подпись истории цен
Что было.
/house-analyticsпри менее чем 8 архивных лотах добирает до 30 соседних домов в радиусе 300 м и возвращаетradius_m. Карточка всё равно писала «История цен в этом доме · только этот дом». Рядом, в шапке того же экрана, стояло «в радиусе 300 м».Что сделано. Заголовок и подпись зависят от
radius_m: при расширении выводится «История цен: дом и соседние · дом и соседние в радиусе N м». Поправлены v2 (mappers.tsиAnalyticsView.tsx, включая aria-label и<title>) и старыйPriceHistoryChart.Тесты
Код возврата снят у самих pytest/vitest. Все прогоны на ветке после rebase на
origin/maina130303c.DATABASE_URL=...localhost:5432/test uv run python -m pytest tests/ -q -p no:cacheprovider→4 failed, 6422 passed, 45 skipped, rc=1.maina130303c:4 failed, 6 passed, rc=1. Этоtest_3466_corridor_tier_a.py(2 теста) иtest_estimator_radius_floor.py(2 теста), ошибкаAttributeError: 'Settings' object has no attribute 'estimate_corridor_clamp_slack'.Settings.postgis/postgis:16-3.4):tests/test_gar_flats_loader.py+tests/test_estimator_target_city_sweep_2583.py→81 passed, rc=0. Три живых ГАР-теста реально исполнились, а не пропустились. Новый живой тест добавлен вskip_allowlist.txt.ruff check app tests→ rc=0.ruff format --checkпо изменённым файлам → rc=0.npx tsc --noEmit→ rc=0;npx vitest run→36 files, 314 passed, rc=0;npm run lint→ rc=0, ошибок 0.uv run python -m pytest -q→no tests ran, rc=5. В пакете нет тестов, и пакет в PR не менялся: из него только читаетсяCITY_DISPLAY_NAMES.Фальсификация
Для каждого пункта ломал фикс вручную на копии исходника (копия лежит в scratchpad), прогонял тест, восстанавливал файл и проверял
diff -q.H1. В
_TARGET_CITIESзаменил|наor, то есть вернул прежний словарь из 24 имён.28 failed, 24 passed, rc=1:14 сделок вместо 4: это коридор по «Ленина» всей области, 10 из них екатеринбургские.
H5, а. Убрал
AND CAST(h.region_code AS text) = gp.region_code. Тест на живой Postgres,1 failed, 28 passed, rc=1:Прогон региона 66 проставил екатеринбургский guid подмосковному дому.
H5, б. Отключил снятие чужих guid.
1 failed, 28 passed, rc=1:M2, а. В маппере
radiusM = 0, вPriceHistoryChartусловие заменил наfalse ?.3 failed | 1 passed, rc=1:M2, б. В
AnalyticsViewвернул константный заголовок.1 failed | 3 passed, rc=1, падает тест «экран v2 печатает подпись из данных, а не константу».Приёмка на проде (после деплоя)
Критерии записаны до деплоя. Срок: 2026-09-20.
docker exec tradein-backend python -c "from app.services.estimator import _resolve_target_city as r; print(r('Реж, Ленина, 12'), r('Карпинск, Ленина, 5'))"должна напечататьреж карпинск. Старый код печатаетNone None, так что маркер отличает версии._fetch_dkp_corridor(SessionLocal(), address='Реж, Ленина, 12', rooms=2, area=45.0, city='реж'), там только SELECT.countдолжен совпасть со сделками Режа (deals.city='Реж', улица Ленина, площадь ±15%, 12 мес.), а не со сделками «Ленина» по всей области.python -m app.tasks.gar_flats_load --match-only --region 66, затем--region 77и--region 50. Запускает владелец, это запись в прод.SELECT h.region_code, g.region_code, count(*) FROM houses h JOIN gar_house_flats g ON g.house_guid = h.gar_house_guid WHERE h.region_code::text <> g.region_code GROUP BY 1,2должен вернуть 0 строк. База на 2026-09-17: 578 / 340 / 1371 / 497.tradein-frontendдолжна появиться строка «дом и соседние». Открыть в v2 раздел «Аналитика дома» для оценки, где шапка показывает «в радиусе 300 м»: заголовок карточки должен быть «История цен: дом и соседние». Проверять на скриншоте.Деплой
Миграций нет. Меняются образы backend (он же в scraper) и frontend: пересоздадутся
tradein-backend,tradein-scraperиtradein-frontend. Перед мержем проверитьSELECT count(*) FROM scrape_runs WHERE status='running': дренаж деплоя ждёт не больше 5 минут, потом пересоздаёт scraper.Что остаётся в #2583
confidence_explanationв сводке и подсказке, радиус на карте.analog_tier,address_precisionиmanual_review_recommendedv2 не показывает, и нужно ли их показывать, решает владелец.Refs #2583
🤖 Generated with Claude Code