Матч ГАР работает по любому региону, а не только по Екатеринбургу #3523

Merged
lekss361 merged 1 commit from feat/gar-flats-per-region into main 2026-09-15 06:59:03 +00:00
Owner

Проблема

Город-фильтр матча ГАР был константой «Екатеринбург» в gar_flats_load. Для Москвы и области экран доли квартир в продаже мёртв: по Москве заполнено 388 домов из 17 453 против 4 821 из 10 159 в Екатеринбурге.

Решение

Фильтр выбирается по региону. Единственный источник решения — реестр REGIONS_REQUIRING_CITY_FILTER, где сейчас лежит только код 66, а само значение берётся из city_token реестра регионов, а не хардкодится строкой второй раз. Регион 66 без явного --city даёт прежнее поведение байт в байт, Москва и область получают фильтр None.

Сентинел CITY_FILTER_AUTO отличает «не передали» от явного «фильтр отключён»: --city "" по-прежнему отключает фильтр для любого региона, включая 66.

Почему области нельзя просто снять фильтр и уйти

Канон адреса (миграция 144) режет всё, кроме улицы и номера дома, населённый пункт в нём не остаётся. Без фильтра «Ленина 5» из десятков городов области схлопнулась бы в один канон, а старый DISTINCT ON молча пришил бы её к дому одного города вместо другого.

Поэтому запрос теперь считает canon_hits оконной функцией и матчит только однозначные каноны. Неоднозначный канон не угадывается по максимальному числу квартир, а пропускается: пропущенный дом лучше неверно приписанного. При заданном фильтре (регион 66) ограничение не срабатывает, план и результат прежние.

Проверено

pytest -k "gar or flats or building" — 262 passed, 3 skipped по allowlist. Добавлен живой тест на Postgres, который проверяет, что неоднозначный канон без фильтра не матчится. ruff check и format чисты.

Дамп ГАР качается и раскладывается отдельным ops-шагом, руководство обновлено.

## Проблема Город-фильтр матча ГАР был константой «Екатеринбург» в `gar_flats_load`. Для Москвы и области экран доли квартир в продаже мёртв: по Москве заполнено 388 домов из 17 453 против 4 821 из 10 159 в Екатеринбурге. ## Решение Фильтр выбирается по региону. Единственный источник решения — реестр `REGIONS_REQUIRING_CITY_FILTER`, где сейчас лежит только код 66, а само значение берётся из `city_token` реестра регионов, а не хардкодится строкой второй раз. Регион 66 без явного `--city` даёт прежнее поведение байт в байт, Москва и область получают фильтр `None`. Сентинел `CITY_FILTER_AUTO` отличает «не передали» от явного «фильтр отключён»: `--city ""` по-прежнему отключает фильтр для любого региона, включая 66. ## Почему области нельзя просто снять фильтр и уйти Канон адреса (миграция 144) режет всё, кроме улицы и номера дома, населённый пункт в нём не остаётся. Без фильтра «Ленина 5» из десятков городов области схлопнулась бы в один канон, а старый `DISTINCT ON` молча пришил бы её к дому одного города вместо другого. Поэтому запрос теперь считает `canon_hits` оконной функцией и матчит только однозначные каноны. Неоднозначный канон не угадывается по максимальному числу квартир, а пропускается: пропущенный дом лучше неверно приписанного. При заданном фильтре (регион 66) ограничение не срабатывает, план и результат прежние. ## Проверено `pytest -k "gar or flats or building"` — 262 passed, 3 skipped по allowlist. Добавлен живой тест на Postgres, который проверяет, что неоднозначный канон без фильтра не матчится. ruff check и format чисты. Дамп ГАР качается и раскладывается отдельным ops-шагом, руководство обновлено.
lekss361 added 1 commit 2026-09-15 06:36:25 +00:00
fix(tradein): матч ГАР-знаменателя выбирает city-фильтр по региону, не по хардкоду ЕКБ
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 16s
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 6m4s
5e963c4379
DEFAULT_CITY_FILTER="Екатеринбург" был жёсткой CLI-константой, поэтому запуск лоадера
для региона 77 (Москва) или 50 (область) молча резал бы матч под несуществующий
город. Теперь default_city_filter_for_region() решает по региону (источник имени —
REGIONS[66].city_token из regions.py): 66 получает byte-for-byte прежний фильтр,
77/50 — без фильтра (объяснено комментарием у REGIONS_REQUIRING_CITY_FILTER).

Заодно закрыт реальный, а не декоративный риск: без city-фильтра canon-ключ адреса
(tradein_canon_addr, мигр. 144) не несёт населённый пункт, поэтому у области (50, без
одного доминирующего города) одноимённые улицы разных городов схлопывались бы в один
canon и матчер молча приписывал бы дом одного города дому другого. _MATCH_SQL теперь
считает canon_hits (число разных ГАР-домов на canon в выборке) и матчит только
однозначные canon — неоднозначные пропускаются, а не угадываются по max(flat_count).
С city-фильтром (регион 66) это ограничение не действует, поведение не меняется.

Раннбук дополнен шагами для 77/50 (какие папки архива распаковывать) и актуальным
источником URL дампа ФИАС (GetLastDownloadFileInfo, т.к. прямой URL меняется еженедельно).
lekss361 merged commit d7aaa00326 into main 2026-09-15 06:59:03 +00:00
lekss361 deleted branch feat/gar-flats-per-region 2026-09-15 06:59:04 +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#3523
No description provided.