- listings.phones: миграция 166 обнуляет данные; cian.py + scraper-kit
serp.py (golden-parity зеркало) перестают читать offer.get("phones") на
входе — write-path выключен у источника, колонка/поле в модели остаются.
Мёртвая запись "phones" в LISTING_FIELD_PRIORITY убрана.
- trade_in_estimates.client_name/client_phone: миграция 167 дропает колонки;
синхронно убраны из TradeInEstimateInput, обоих INSERT в estimator.py
(основной путь + _empty_estimate), frontend TradeInEstimateInput и
CRM-блока EstimateForm (поля "Имя клиента"/"Телефон").
- sentry_scrub.py и management_companies.phones не тронуты — вне scope.
Три гарда в match_or_create_house (+ P2 в match_house_readonly):
- P1: не матчить/алиасить голую улицу (normalized_address без номера дома)
- P2: отклонять Tier-3 гео-кандидата, если номера домов различаются
- P3: не цементировать слабый гео-матч (0.7) как alias-ключ здания
Хелперы has_house_number/house_number_token (по хвостовому токену —
«улица 8 марта» это улица, не дом). Корень mis-bucketing: house 131237
стянул 8 разных Мамина-номеров + голую улицу. Юнит + поведенческие тесты,
603 matching/normalize/house зелёных. Аффектит только НОВЫЕ матчи;
чистка cemented-данных — отдельной миграцией (P4).
Estimator теперь резолвит target-адрес в КАНОНИЧЕСКИЙ house_id (read-only,
без создания записи) и матчит аналоги по listings.house_id_fk — детерминированный
Tier S «тот же дом» вместо хрупкого address-string prefix match. 99% листингов
слинкованы с houses, поэтому это срабатывает уже сегодня и точнее работает между
разнородными источниками (Avito/Cian/Yandex форматируют адрес по-разному).
- matching/houses.py: match_house_readonly() — read-only target→house резолвер
(cadastr_exact → fingerprint → geo_proximity 50m), без INSERT / house_sources /
advisory lock. Возвращает None если уверенного match нет.
- estimator.estimate_quality: после geocode+DaData резолвит target_house_id
(cadastr от DaData → cadastr_exact заработает по мере backfill houses), graceful.
- estimator._fetch_analogs: новый param target_house_id + канонический Tier S
(WHERE house_id_fk = target) ПЕРЕД address-prefix Tier S (теперь fallback).
tier label 'S' сохранён (frontend уже рендерит).
Эффект: вместо «похожие в радиусе 800-1000м» — «вот что в ЭТОМ доме», прямой
выигрыш в точности оценки. Foundation под cadastr/FIAS exact match (DaData Q1/Q3).
Tests: 9 новых (match_house_readonly tiers + never-inserts + canonical Tier S
fires/fallback/too-few). Ruff clean. Pre-existing 4 fail в test_estimator_source_quota
(unpack 2≠3, красные на main до этого PR) — не затронуты.