Бэктест оценщика берёт тип дома из справочника домов, как боевая оценка — штраф за тип дома впервые участвует в замере #3571
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#3571
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/backtest-house-type"
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?
Частично по #2862. Issue остаётся открытым: основную его часть (перевод кода материала стен Росреестра в тип дома) без справочника и решения владельца делать нельзя, см. раздел «Что не сделано».
Что было
deals(source='rosreestr') — 434 911 строк,house_typeзаполнен у 0 (регион 50: 0 из 113 351, 66: 0 из 108 623, 77: 0 из 212 937).scripts/backtest_estimator.py) передаётdeal.house_typeво все четыре вызова_fetch_analogs. Штраф за несовпадение типа дома в SQL срабатывает только при условииtarget_house_type IS NOT NULL, поэтому ни в одном прогоне он не включался.estimate_qualityс #3234 берёт тип дома изhouses, если его нет в форме: сначала по резолвленному house_id, иначе по ближайшему дому в радиусе 60 м. С #3257 форма ещё и предзаполняется из того же справочника. Бэктест этот шаг не повторял, даже в режиме--resolve-house-id, который и существует для паритета с продом. На этом режиме строились калибровки вconfig.pyи множители вилки в #3540.Что сделано
--resolve-house-id, если у сделки нет типа дома, бэктест вызывает тот же_lookup_house_facts, что и боевая оценка, с теми же аргументами: резолвленный house_id, а без него координаты сделки. Если тип дома у сделки уже есть, справочник его не перезаписывает — так же на проде значение из формы главнееhouses.house_id_resolutionдобавлен счётчикhouse_type_from_houses: сколько сделок получили тип из справочника. Если он равен нулю, штраф в прогоне не участвовал.housesне подставляются намеренно, хотя боевая оценка берёт их тем же вызовом.deals.total_floorsтоже пуст у 0 из 434 911. Если подставить и их, метрики сдвинутся ещё и из-за этажного фактора и когорт по году, и эффект одного типа дома уже не выделить. А issue просит измерить именно его. Этот разрыв с продом остаётся, и его стоит закрыть отдельным PR с отдельным замером.replay_fixture, 277 сделок) не затронут: он воспроизводит уже отобранные аналоги из фикстуры.Ожидаемый охват невелик. Оценка по той же выборке, что у калибровочных прогонов: регион 66,
--since 2025-06-01 --spread scattered --seed 42, первые 300 сделок, только ветка «ближайший дом в 60 м». Дом нашёлся у 110 сделок из 300, тип дома заполнен у 13 (4.3%). Сопоставление по адресу (match_house_readonly) может добавить ещё какое-то число. Точное значение покажет счётчик.Что не сделано и почему
Колонка во внешней таблице, соответствие кодов, загрузчик, backfill. У источника (
gendesign-postgres,rosreestr_deals) материал стен закодирован по справочнику 126-УНСИ:061001001001,061001005000,061001007001и т.д., плюс составные значения вида061001006001;061001006002. Сделки ДКП региона 66, топ по числу: пустой код — 70 770,061001001001— 40 547,061001005000— 38 150,061001007001— 19 328,061001003000— 13 662. Расшифровки кодов в репозитории нет (git grep 061001находит только схему). Какой код считатьpanel,monolith,blockилиotherи как разбирать составные значения — это решение по справочнику, а не по коду. Сам issue прямо запрещает соответствие «на глаз»: неверный тип хуже пустого. Колонкуwall_material_codeво внешней таблице без такого соответствия заводить не стал: у неё не было бы ни одного потребителя. Номер миграции МЕРА 323 не использован.Попутная находка (не чинил, касается и прода)
houses.house_typeсодержит значения не из словаря:Монолитный(6),Панельный(6),Кирпичный(5),Монолитно кирпичный(3),Блочный(1),wireframe(1). У активных объявлений ровно 6 кодов: monolith, brick, panel, monolith_brick, block, wood. Для этих домов проверкаhouse_type <> targetистинна у каждого аналога, и штраф бьёт по всем подряд — и на проде, и теперь в бэктесте.Тесты
tests/test_backtest_estimator.py: 71 passed, rc=0. Два новых теста проверяют значения, а не текст:test_full_backtest_takes_house_type_from_houses_like_prod— пустой тип сделки становитсяpanelв каждом вызове_fetch_analogs; свой типbrickу второй сделки сохраняется; справочник запрошен один раз сtarget_house_id=77, lat, lon; счётчик = 1.test_full_backtest_without_flag_keeps_house_type_untouched— без флага справочник не вызывается, тип остаётсяNone, блокаhouse_id_resolutionв выводе нет.6234 passed, 44 skipped, rc=0.6372 passed, 4 failed, 44 skipped. Эти 4 падения уже есть в main и не связаны с этим PR:test_3466_corridor_tier_a.py(2) иtest_estimator_radius_floor.py(2) падают сAttributeError: 'Settings' object has no attribute 'estimate_corridor_clamp_min_n'. Причина — #3556 превратил эти настройки в код, а тесты #3554 всё ещё к ним обращаются. Этот PR меняет только два файла бэктеста.ruff check app tests— All checks passed;ruff format --checkна обоих файлах — already formatted.Фальсификация
deal = dataclasses.replace(...)→pass), rc=1:if deal.house_type is None→if True), rc=1:После каждого прогона исходник восстанавливал из копии и проверял через
diff -q.Приёмка на проде (до 2026-09-20)
Проверять не заполненность колонки, а то, сработал ли механизм и сдвинулись ли метрики. После деплоя в
tradein-backendзапустить два прогона на одном срезе (только чтение из БД):--engine full --resolve-house-id --region 66 --since 2025-06-01 --spread scattered --seed 42 --sample 300 --json— на коде до этого PR и после него.house_id_resolution.house_type_from_houses> 0; по оценке выше ожидается порядка 13 и больше из 300. Ноль означает, что подстановка не исполнялась, и сравнивать метрики бессмысленно.🤖 Generated with Claude Code