fix(tradein/dedup): canon cluster-key + geo/digit guard в house-merge (P4c) #2085

Merged
lekss361 merged 1 commit from fix/tradein-house-dedup-canon into main 2026-06-28 21:53:16 +00:00
Owner

Проблема — дубли house-записей

Одно здание = 2+ house-записи из-за разного написания адреса → доля в sale-share расщеплена: Вайнера 66 (10930 «ул. Вайнера,66» + 11320 «улица Вайнера, 66») показывает 28.6% + 7.1% вместо ~36%. Также Мраморская 34к4 (8110+177233). merge_duplicate_houses кластеризовал по exact lower(trim(address)) → варианты не схлопывались.

Фикс — merge_duplicate_houses

Ключ кластера: lower(trim(address))tradein_canon_addr(address) (ул→улица, стрип город/район/«россия»/«м-н», корпус сохранён — verified мраморская34к2мраморская34к4).

Поскольку canon стрипует город → 2 гарда против over-merge (на основе прод dry-run):

  • Гео ≤250м (ST_DistanceSphere, keeper-geom через first_value): dry-run показал same-canon кластеры до 20км (одноимённые улицы в разных городах региона-66 — Юбилейная/Восточная/Свердлова). Города в км+ → 250м безопасно от cross-town, и покрывает geocode-разброс дубля (Мраморская 34к4 = 222м).
  • Digit-guard: canon обязан содержать цифру (номер дома) — исключает вырожденные екатеринбург/сооружение (адреса без улицы).

NULL-geom или >250м лузеры → остаются раздельно (conservative, никогда не over-merge). Re-pointing listings/house_sources/aliases, audit, dry-run, идемпотентность — не тронуты.

Проверки

  • ruff clean; pytest test_house_dedup_merge26 passed (+ digit-guard assert; 2 real-DB теста self-skip без тестовой БД).
  • Прод dry-run preview (read-only) подтвердил: cross-town spreads до 20км (нужен гео-гард), вырожденные canon (нужен digit-guard), target-дубли Вайнера 2м / Мраморская 34к4 222м.

После мержа (делаю сам)

  1. Deploy.
  2. merge_duplicate_houses(dry_run=True) на проде → preview (сколько кластеров/лузеров) → self-verify нет over-merge.
  3. Применяю реальный мерж → verify Вайнера 66 / Мраморская 34к4 = 1 house-запись, доля собрана.

Это P4c (последний видимый баг) в серии sale-share: #2077/#2080/#2082/#2083/#2084.

## Проблема — дубли house-записей Одно здание = 2+ house-записи из-за разного написания адреса → доля в sale-share расщеплена: Вайнера 66 (10930 «ул. Вайнера,66» + 11320 «улица Вайнера, 66») показывает 28.6% + 7.1% вместо ~36%. Также Мраморская 34к4 (8110+177233). `merge_duplicate_houses` кластеризовал по **exact** `lower(trim(address))` → варианты не схлопывались. ## Фикс — `merge_duplicate_houses` Ключ кластера: `lower(trim(address))` → **`tradein_canon_addr(address)`** (ул→улица, стрип город/район/«россия»/«м-н», **корпус сохранён** — verified `мраморская34к2`≠`мраморская34к4`). Поскольку canon стрипует город → 2 гарда против over-merge (на основе **прод dry-run**): - **Гео ≤250м** (`ST_DistanceSphere`, keeper-geom через `first_value`): dry-run показал same-canon кластеры до **20км** (одноимённые улицы в разных городах региона-66 — Юбилейная/Восточная/Свердлова). Города в км+ → 250м безопасно от cross-town, и покрывает geocode-разброс дубля (Мраморская 34к4 = 222м). - **Digit-guard**: canon обязан содержать цифру (номер дома) — исключает вырожденные `екатеринбург`/`сооружение` (адреса без улицы). NULL-geom или >250м лузеры → остаются раздельно (conservative, никогда не over-merge). Re-pointing listings/house_sources/aliases, audit, dry-run, идемпотентность — **не тронуты**. ## Проверки - ruff clean; pytest `test_house_dedup_merge` → **26 passed** (+ digit-guard assert; 2 real-DB теста self-skip без тестовой БД). - Прод dry-run preview (read-only) подтвердил: cross-town spreads до 20км (нужен гео-гард), вырожденные canon (нужен digit-guard), target-дубли Вайнера 2м / Мраморская 34к4 222м. ## После мержа (делаю сам) 1. Deploy. 2. `merge_duplicate_houses(dry_run=True)` на проде → preview (сколько кластеров/лузеров) → self-verify нет over-merge. 3. Применяю реальный мерж → verify Вайнера 66 / Мраморская 34к4 = 1 house-запись, доля собрана. Это P4c (последний видимый баг) в серии sale-share: ✅ #2077/#2080/#2082/#2083/#2084.
lekss361 added 1 commit 2026-06-28 21:51:35 +00:00
fix(tradein/dedup): canon cluster-key + geo/digit guard в house-merge
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
7cf6267b48
merge_duplicate_houses кластеризовал дома по exact lower(trim(address)) →
варианты написания одного здания (ул. Вайнера,66 vs улица Вайнера, 66) не
схлопывались, расщепляя долю в sale-share. Ключ кластера → tradein_canon_addr
(ул→улица, стрип город/район, КОРПУС сохранён). Гарды против over-merge:
- гео ≤250м (canon стрипует город; прод-дубли Мраморская 34к4 в 222м; города
  региона-66 в км+ → 250м безопасно от cross-town);
- canon обязан содержать цифру (номер дома) — исключает вырожденные
  «екатеринбург»/«сооружение».
Re-pointing/audit/dry-run/идемпотентность не тронуты. 26 passed.
lekss361 merged commit 31e7816967 into main 2026-06-28 21:53:16 +00:00
lekss361 deleted branch fix/tradein-house-dedup-canon 2026-06-28 21:53:16 +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#2085
No description provided.