feat(tradein/domklik): пробросить isRosreestrApproved в колонку #3068

Merged
lekss361 merged 2 commits from feat/domklik-serp-field-passthrough into main 2026-08-23 21:49:44 +00:00
Owner

Пункт 1 из #3064. Пункт 2 разобран и сознательно не сделан — см. ниже, там нашлось кое-что поинтереснее самой задачи.

Что было

BFF-ответ Домклика отдаёт isRosreestrApproved, поле уже парсилось — и оседало только в raw_payload jsonb. В колонке is_rosreestr_checked при этом у всех 1 338 активных domklik-листингов было NULL.

Соответствие однозначное и подтверждается соседним провайдером: у cian offer["isRosreestrChecked"] → is_rosreestr_checked (cian/serp.py:1014) — прямой passthrough без трансформаций. Здесь ровно то же.

registry_match не трогается: судя по 011_listings_alter.sql:54 («Совпадают площадь, адрес и этаж») и по тому, что пишет его только avito/detail.py, это сверка ЕГРН по трём атрибутам с детальной страницы, а не SERP-флаг «проверено». Другая величина, несмотря на похожее название.

Почему пункт 2 (is_pro_seller из agency_name) не сделан

Он был написан, а потом снят — после проверки того, что эта колонка вообще означает. Оказалось, что единого смысла у неё нет уже сейчас:

Провайдер Источник значения Смысл
cian offer["isPro"] платная PRO-подписка (019_listings_alter_cian.sql:43: «PRO подписка у продавца»)
yandex author.category ∈ {AGENCY, AGENT} (yandex/serp.py:203-220) категория продавца

Это два разных признака в одной колонке. «Есть непустой agency_name» стал бы третьим — и поехал бы в оценщик trade-in наравне с первыми двумя, причём у domklik agency_name заполнен у 100 % записей, то есть колонка разом получила бы 1 338 значений с новой семантикой.

Правильный ход — сначала решить, что is_pro_seller означает, и привести к одному смыслу всех троих. Это отдельная задача про смысл данных, а не проброс поля. Записано в #3064.

Побочно это же снимает пункт 2 и из #3063 (там я предполагал, что «паттерн уже есть у cian/avito» — оказалось, что нет).

Test plan

  • Новый тест на фикстуре domclick_bff_offers_sample.json — она до сих пор не была подключена ни к одному тесту
  • Фальсификация: до правки тест падал на assert lot.is_rosreestr_checked is TrueAssertionError: assert None is True, при том что raw_payload["isRosreestrApproved"] == True уже присутствовал — то есть тест ловит именно потерю при перекладке, а не отсутствие данных
  • Проверяется и отрицательный случай: у item без ключа isRosreestrApproved результат None, а не False. Отсутствие данных не то же самое, что «проверено — не сходится»; False поехал бы в оценщик как утверждение о квартире
  • Регрессия: 114 passed, 1 skipped (-k domclick)
  • ruff check с проектным конфигом — чисто

Осталось в #3064

Пункт 3 — flatComplex.id/slughouse_source / house_ext_id. Он весомее косметики: без этой привязки domklik-листинги вообще не попадают в house-matching (нет дедупа на уровне дома, нет аналитики по ЖК). Но там нужна миграция и проверка матчинга — отдельный заход.

Refs #3064

Пункт 1 из #3064. Пункт 2 разобран и **сознательно не сделан** — см. ниже, там нашлось кое-что поинтереснее самой задачи. ## Что было BFF-ответ Домклика отдаёт `isRosreestrApproved`, поле **уже парсилось** — и оседало только в `raw_payload` jsonb. В колонке `is_rosreestr_checked` при этом у всех **1 338** активных domklik-листингов было NULL. Соответствие однозначное и подтверждается соседним провайдером: у cian `offer["isRosreestrChecked"] → is_rosreestr_checked` (`cian/serp.py:1014`) — прямой passthrough без трансформаций. Здесь ровно то же. `registry_match` **не трогается**: судя по `011_listings_alter.sql:54` (*«Совпадают площадь, адрес и этаж»*) и по тому, что пишет его только `avito/detail.py`, это сверка ЕГРН по трём атрибутам с детальной страницы, а не SERP-флаг «проверено». Другая величина, несмотря на похожее название. ## Почему пункт 2 (`is_pro_seller` из `agency_name`) не сделан Он был написан, а потом снят — после проверки того, что эта колонка вообще означает. Оказалось, что **единого смысла у неё нет уже сейчас**: | Провайдер | Источник значения | Смысл | |---|---|---| | cian | `offer["isPro"]` | **платная PRO-подписка** (`019_listings_alter_cian.sql:43`: «PRO подписка у продавца») | | yandex | `author.category ∈ {AGENCY, AGENT}` (`yandex/serp.py:203-220`) | **категория продавца** | Это два разных признака в одной колонке. «Есть непустой `agency_name`» стал бы третьим — и поехал бы в оценщик trade-in наравне с первыми двумя, причём у domklik `agency_name` заполнен у **100 %** записей, то есть колонка разом получила бы 1 338 значений с новой семантикой. Правильный ход — сначала решить, что `is_pro_seller` означает, и привести к одному смыслу всех троих. Это отдельная задача про смысл данных, а не проброс поля. Записано в #3064. Побочно это же снимает пункт 2 и из #3063 (там я предполагал, что «паттерн уже есть у cian/avito» — оказалось, что нет). ## Test plan - [x] Новый тест на фикстуре `domclick_bff_offers_sample.json` — она до сих пор не была подключена ни к одному тесту - [x] **Фальсификация:** до правки тест падал на `assert lot.is_rosreestr_checked is True` → `AssertionError: assert None is True`, при том что `raw_payload["isRosreestrApproved"] == True` уже присутствовал — то есть тест ловит именно потерю при перекладке, а не отсутствие данных - [x] Проверяется и отрицательный случай: у item без ключа `isRosreestrApproved` результат `None`, а **не** `False`. Отсутствие данных не то же самое, что «проверено — не сходится»; `False` поехал бы в оценщик как утверждение о квартире - [x] **Регрессия:** `114 passed, 1 skipped` (`-k domclick`) - [x] `ruff check` с проектным конфигом — чисто ## Осталось в #3064 Пункт 3 — `flatComplex.id/slug` → `house_source` / `house_ext_id`. Он весомее косметики: без этой привязки domklik-листинги вообще не попадают в house-matching (нет дедупа на уровне дома, нет аналитики по ЖК). Но там нужна миграция и проверка матчинга — отдельный заход. Refs #3064
lekss361 added 2 commits 2026-08-23 21:36:26 +00:00
BFF-ответ Домклика уже парсит isRosreestrApproved и seller.company/agent
(agency_name), но клал их только в raw_payload jsonb — на проде обе колонки
is_rosreestr_checked и is_pro_seller у всех 1338 активных domklik-листингов
были 100% NULL, хотя данные для их заполнения были в наличии всегда.

- is_rosreestr_checked: прямой passthrough isRosreestrApproved (mirror
  cian serp.py: offer.get("isRosreestrChecked") -> is_rosreestr_checked).
  НЕ то же самое, что listings.registry_match (Avito-специфичная сверка
  "площадь/адрес/этаж совпадают" из detail-страницы, заполняется только
  avito/detail.py) — поэтому registry_match не трогаем.
- is_pro_seller выводится из agency_name: agency_name is None -> None
  (нет данных о продавце), иначе bool(agency_name). agency_name="" на
  практике не возникает (_extract_agency_name уже схлопывает whitespace-only
  в None), но проверка сделана через `is not None`, а не `!= ""`, чтобы
  случайно не превратить None в True.

Refs #3064
fix(tradein/domklik): убрать вывод is_pro_seller — колонка уже перегружена
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m33s
7f829ccc61
Проверка после написания: у is_pro_seller НЕТ единого смысла, из-за
которого её можно было бы выводить из agency_name.

  cian   — offer["isPro"], флаг ПЛАТНОЙ PRO-подписки
           (019_listings_alter_cian.sql:43: «PRO подписка у продавца»)
  yandex — author.category in {AGENCY, AGENT}, категория продавца
           (yandex/serp.py:203-220)

Это уже два разных смысла в одной колонке. «Есть непустой agency_name»
стал бы третьим — и поехал бы в оценщик trade-in наравне с первыми двумя,
причём у domklik agency_name заполнен у 100% записей, то есть колонка
разом получила бы 1338 значений с новой семантикой.

Правильный ход — сначала решить, что эта колонка вообще означает, и
привести к одному смыслу всех троих. Это отдельная задача, не проброс
поля. Здесь остаётся только isRosreestrApproved, у которого соответствие
однозначное и подтверждается cian (offer["isRosreestrChecked"] ->
is_rosreestr_checked, cian/serp.py:1014) — прямой passthrough.

registry_match не трогается: судя по 011_listings_alter.sql:54
(«Совпадают площадь, адрес и этаж») и по тому, что его пишет только
avito/detail.py, это сверка ЕГРН по трём атрибутам с детальной страницы,
а не SERP-флаг «проверено».

Проверено: 114 passed, 1 skipped (-k domclick).

Refs #3064
lekss361 merged commit 4aaa021b62 into main 2026-08-23 21:49:44 +00:00
lekss361 deleted branch feat/domklik-serp-field-passthrough 2026-08-23 21:49:45 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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#3068
No description provided.