fix(tradein/domclick): дом-поля карточки → houses, backfill total_units/material_* из raw_payload (миграция 284) #3356

Merged
bot-backend merged 2 commits from fix/3253-domclick-house-fields into main 2026-09-05 18:26:19 +00:00
Collaborator

Refs #3253 (пп. 1, 2, 4; п.3 domclick_building_guid как ключ дома — отдельно). Данные для аналогов оценщика: houses.total_units = 0 у ВСЕХ источников при том, что у Домклика quarters_count лежит в listings.raw_payload.

П.1 — откуда 400 «домклик-домов» (фактами)

Дома домклику создаёт SERP-путь (base.py:1067 _link_listing_to_house → match_or_create_house) для каждого лота; houses.source = кто дом впервые заминтил. Тиры матчера сажают домклик-объявления на уже существующие дома avito/cian/derived — 400 это дома, где Домклик пришёл первым, не покрытие. Второй канал потерь — терминал no_house_number (безномерной адрес без кадастра → дом не пишется). Detail-путь до правки houses не трогал вовсе.

П.2 — перенос

save_detail_enrichment: второй UPDATE houses через listings.house_id_fk — калька с avito _fill_house_params_from_detail (#3036): quarters_count → total_units, wall_type → material_walls, floor_type → material_floors, COALESCE в SET и в WHERE-гейте (непустое не затирается). Серия/энергоэффективность/подъезды — остаются в raw_payload (колонок нет, схему не заводили).

П.4 — миграция 284

Backfill из raw_payload через house_id_fk; победитель при нескольких объявлениях DISTINCT ON (house_id_fk) ORDER BY detail_enriched_at DESC NULLS LAST, id DESC; идемпотентно; lock_timeout (гейт: 41 миграция ok).

Замер радиуса на проде ДО мержа (SQL воркера): houses_touchable=3590, заполнится total_units=3198, material_walls=367, material_floors=3424, конфликтов (непустое ≠ raw) = 0 — COALESCE ничего не перепишет.

Тесты

712 passed, 11 skipped (-k domclick/house). Фальсификация (откат кодового хунка): UPDATE houses не исполнен; операторы: ['UPDATE listings …'].

Прод-приёмка после деплоя

SELECT count(*) FILTER (WHERE total_units IS NOT NULL) FROM houses ≈ +3198; следующий domclick detail-прогон обновляет дома (лог/счётчик).

Refs #3253 (пп. 1, 2, 4; п.3 `domclick_building_guid` как ключ дома — отдельно). Данные для аналогов оценщика: `houses.total_units` = 0 у ВСЕХ источников при том, что у Домклика `quarters_count` лежит в `listings.raw_payload`. ## П.1 — откуда 400 «домклик-домов» (фактами) Дома домклику создаёт SERP-путь (`base.py:1067 _link_listing_to_house → match_or_create_house`) для каждого лота; `houses.source` = кто дом **впервые** заминтил. Тиры матчера сажают домклик-объявления на уже существующие дома avito/cian/derived — 400 это дома, где Домклик пришёл первым, не покрытие. Второй канал потерь — терминал `no_house_number` (безномерной адрес без кадастра → дом не пишется). Detail-путь до правки `houses` не трогал вовсе. ## П.2 — перенос `save_detail_enrichment`: второй UPDATE `houses` через `listings.house_id_fk` — калька с avito `_fill_house_params_from_detail` (#3036): `quarters_count → total_units`, `wall_type → material_walls`, `floor_type → material_floors`, COALESCE в SET и в WHERE-гейте (непустое не затирается). Серия/энергоэффективность/подъезды — остаются в raw_payload (колонок нет, схему не заводили). ## П.4 — миграция 284 Backfill из raw_payload через house_id_fk; победитель при нескольких объявлениях `DISTINCT ON (house_id_fk) ORDER BY detail_enriched_at DESC NULLS LAST, id DESC`; идемпотентно; lock_timeout (гейт: 41 миграция ok). **Замер радиуса на проде ДО мержа** (SQL воркера): `houses_touchable=3590`, заполнится `total_units=3198`, `material_walls=367`, `material_floors=3424`, **конфликтов (непустое ≠ raw) = 0** — COALESCE ничего не перепишет. ## Тесты `712 passed, 11 skipped` (-k domclick/house). Фальсификация (откат кодового хунка): `UPDATE houses не исполнен; операторы: ['UPDATE listings …']`. ## Прод-приёмка после деплоя `SELECT count(*) FILTER (WHERE total_units IS NOT NULL) FROM houses` ≈ +3198; следующий domclick detail-прогон обновляет дома (лог/счётчик).
bot-backend added 1 commit 2026-09-05 18:01:24 +00:00
fix(tradein/domclick): дом-поля карточки → houses, backfill total_units (#3253)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 11s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m4s
2532bcbe27
Парсер карточки Домклика читал houseInfo.info и складывал блок дома целиком
в listings.raw_payload; в houses не переносил ничего. Замер 29.08: total_units
= 0 у ВСЕХ источников, хотя quarters_count уже лежал в собранных payload'ах.

save_detail_enrichment получает второй оператор — тот же fill-only паттерн, что
у avito (#3036), связь через listings.house_id_fk: quarters_count → total_units,
wall_type → material_walls, floor_type → material_floors. COALESCE в SET и в
WHERE-гейте: непустое значение дома не затирается (у houses есть конкурирующие
писатели — ДОМ.РФ капремонт, Houses Catalog). Серия дома, энергоэффективность и
число подъездов остаются в raw_payload — колонок под них нет, схему не расширяем.

Миграция 284 переливает то же самое задним числом из уже собранных payload'ов,
только в пустые колонки, идемпотентно, под lock_timeout.
Light1YT added 1 commit 2026-09-05 18:19:02 +00:00
fix(tradein/domclick): дом-поля едут в словаре ДОМ.РФ, а не сырьём Домклика
All checks were successful
CI Trade-In / changes (pull_request) Successful in 14s
CI / changes (pull_request) Successful in 16s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m26s
d518efbed1
houses.material_walls уже заполнена словарём ДОМ.РФ (капремонт КР1.2, #2013):
кирпич 2662, железобетонная панель 2107, иное 1850, монолит 754. Ветка писала
туда сырую фразу карточки (Монолитный 2656, Кирпичный 2241, Панельный 1671,
Монолитно-кирпичный 773) — колонка стала бы двухсловарной, и `WHERE
material_walls = 'монолит'` перестал бы видеть весь Домклик. Ровно та болезнь,
которую sale_type уже пережил в #2674.

canon_wall_type / canon_floor_type стоят на границе записи в houses (как
canon_sale_type — на границе записи в listings): Кирпичный→кирпич,
Панельный→железобетонная панель, Монолитный/Монолитно-кирпичный→монолит,
Блочный/Деревянный→иное, Железобетонный→Железобетонные (форма, уже лежащая в
колонке). Незнакомое → None + warning раз на процесс: сырьё в колонку не
попадает никогда, а новое значение словаря видно в логах. В raw_payload сырая
фраза площадки остаётся как была.

Миграция 284 получила тот же CASE lower(...) — иначе backfill залил бы задним
числом ровно то, что код перестал писать. CASE без ELSE: незнакомое → NULL.
bot-backend merged commit e48b4a47d7 into main 2026-09-05 18:26:19 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3356
No description provided.