fix(mera/b2c): житель Серова получал «вы вне области», а подсказки игнорировали выбранный город #2919

Merged
lekss361 merged 1 commit from fix/mera-city-parity into main 2026-08-16 10:09:14 +00:00
Owner

Два дефекта, найденных прогоном сценария глазами посетителя на живом домене.

1. Город предлагали выбрать, но отвечать по нему не умели

Дропдаун на сайте (OBLAST_CITIES, city-registry.ts) и списки покрытия (COVERAGE_GREEN/YELLOW_CITIES, trade_in.py) — одно множество, записанное в двух местах. Разошлись в обе стороны:

предлагали, но не отвечали:  Серов
отвечали, но не предлагали:  Берёзовский, Среднеуральск, Ревда

Житель Серова выбирал свой город из нашего дропдауна и получал:

Этот адрес вне области, по которой мы собираем данные.
Сейчас это Свердловская область: Екатеринбург целиком и ещё несколько городов вокруг.

Про город в той же самой области, который мы ему сами и предложили.

Серов при этом покрыт данными — 363 активных объявления в радиусе 15 км, все свежие (замер по проде). Поэтому он добавлен в жёлтый тир, а не убран из дропдауна; три недостающих города добавлены на фронт.

Шапка city-registry.ts этот риск прямо предсказывала:

Перед добавлением 7-го города — сверить оба списка вручную (codegen/тест на это пока нет).

Теперь тест есть: бэкендовый сьют читает TS-реестр и требует равенства множеств. Плюс проверка, что у каждого города с порогом есть центроид — иначе порог мёртвый, город по координатам не резолвится вовсе.

2. Подсказки не слушались выбранного города

city_hint доезжает до геокодера, но на выдачу не влияет: его смотрит только екатеринбургский кадастровый тир (как признак «речь не про ЕКБ, тир пропускаем»), а DaData-тир ограничен регионом целиком и хинта не принимает.

Замер на проде — выбран Серов, введено «Ленина 1»:

Свердловская обл, Невьянский р-н, пгт Верх-Нейвинский, тер ул. Ленина 19
Свердловская обл, г Красноуральск, тер. ГСК ... по ул. Ленина, ряд 1
г Екатеринбург, пр-кт Ленина, д 1

Человек выбирает верхний вариант и считает чужой дом — ровно баг #2576, ради которого город и спрашивают.

Публичная ручка теперь подставляет город в саму строку запроса. С ним выдача становится серовской целиком:

Свердловская обл, г Серов, ул Ленина, д 1
Свердловская обл, г Серов, поселок Красноглинный, ул Ленина, д 1

Для Екатеринбурга подстановка безвредна — три разных адреса дали тот же результат с префиксом и без, поэтому правило одно на все города, без исключения для основного трафика (исключение пришлось бы поддерживать).

Чинится в публичной ручке, а не в геокодере: там от city_hint зависит поведение закрытого контура (target_city_ambiguous), и менять его смысл ради публичной формы значит трогать чужой контракт.

Фикстура теста

_FAR_AWAY_CITY стояла в 21 км от центра Серова и работала как «далеко от всех центроидов» лишь потому, что Серов не был поддержан. Переехала в Тавду — 271 км до ближайшего центроида, всё ещё Свердловская область.

Проверено

мутация: убрать Серов из покрытия (состояние прода) → падает сверка списков
мутация: не подставлять город в строку              → падает проверка ручки
откат                                               → 21 passed

backend 75 passed, vitest 56 passed, tsc, next lint, next build, isolation guard 41 файл.

city-registry.ts добавлен в paths-фильтр бэкендового лэйна: сверку списков делает бэкендовый тест, и без этой строки правка одного лишь дропдауна её бы не запускала — то есть ровно тем путём, которым списки и разошлись.

Два дефекта, найденных прогоном сценария глазами посетителя на живом домене. ## 1. Город предлагали выбрать, но отвечать по нему не умели Дропдаун на сайте (`OBLAST_CITIES`, `city-registry.ts`) и списки покрытия (`COVERAGE_GREEN/YELLOW_CITIES`, `trade_in.py`) — одно множество, записанное в двух местах. Разошлись в обе стороны: ``` предлагали, но не отвечали: Серов отвечали, но не предлагали: Берёзовский, Среднеуральск, Ревда ``` Житель Серова выбирал **свой** город из **нашего** дропдауна и получал: > Этот адрес вне области, по которой мы собираем данные. > Сейчас это Свердловская область: Екатеринбург целиком и ещё несколько городов вокруг. Про город в той же самой области, который мы ему сами и предложили. Серов при этом покрыт данными — **363 активных объявления** в радиусе 15 км, все свежие (замер по проде). Поэтому он добавлен в жёлтый тир, а не убран из дропдауна; три недостающих города добавлены на фронт. Шапка `city-registry.ts` этот риск прямо предсказывала: > Перед добавлением 7-го города — сверить оба списка вручную (codegen/тест на это пока нет). Теперь тест есть: бэкендовый сьют читает TS-реестр и требует **равенства** множеств. Плюс проверка, что у каждого города с порогом есть центроид — иначе порог мёртвый, город по координатам не резолвится вовсе. ## 2. Подсказки не слушались выбранного города `city_hint` доезжает до геокодера, но на выдачу не влияет: его смотрит только екатеринбургский кадастровый тир (как признак «речь не про ЕКБ, тир пропускаем»), а DaData-тир ограничен регионом целиком и хинта не принимает. Замер на проде — выбран Серов, введено «Ленина 1»: ``` Свердловская обл, Невьянский р-н, пгт Верх-Нейвинский, тер ул. Ленина 19 Свердловская обл, г Красноуральск, тер. ГСК ... по ул. Ленина, ряд 1 г Екатеринбург, пр-кт Ленина, д 1 ``` Человек выбирает верхний вариант и считает чужой дом — ровно баг #2576, ради которого город и спрашивают. Публичная ручка теперь подставляет город в саму строку запроса. С ним выдача становится серовской целиком: ``` Свердловская обл, г Серов, ул Ленина, д 1 Свердловская обл, г Серов, поселок Красноглинный, ул Ленина, д 1 ``` Для Екатеринбурга подстановка безвредна — три разных адреса дали тот же результат с префиксом и без, поэтому правило одно на все города, без исключения для основного трафика (исключение пришлось бы поддерживать). Чинится в публичной ручке, а не в геокодере: там от `city_hint` зависит поведение закрытого контура (`target_city_ambiguous`), и менять его смысл ради публичной формы значит трогать чужой контракт. ## Фикстура теста `_FAR_AWAY_CITY` стояла в 21 км от центра Серова и работала как «далеко от всех центроидов» лишь потому, что Серов не был поддержан. Переехала в Тавду — 271 км до ближайшего центроида, всё ещё Свердловская область. ## Проверено ``` мутация: убрать Серов из покрытия (состояние прода) → падает сверка списков мутация: не подставлять город в строку → падает проверка ручки откат → 21 passed ``` backend 75 passed, `vitest` 56 passed, `tsc`, `next lint`, `next build`, isolation guard 41 файл. `city-registry.ts` добавлен в paths-фильтр **бэкендового** лэйна: сверку списков делает бэкендовый тест, и без этой строки правка одного лишь дропдауна её бы не запускала — то есть ровно тем путём, которым списки и разошлись.
lekss361 added 1 commit 2026-08-16 10:03:49 +00:00
fix(mera/b2c): житель Серова получал «вы вне области», а подсказки игнорировали выбранный город
All checks were successful
CI / changes (pull_request) Successful in 10s
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 / frontend-checks (pull_request) Successful in 1m6s
CI Trade-In / backend-tests (pull_request) Successful in 4m50s
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Successful in 48s
73c4c487ed
Два дефекта, найденных прогоном сценария глазами посетителя на живом домене.

## 1. Город предлагали выбрать, но отвечать по нему не умели

Дропдаун на сайте (`OBLAST_CITIES`, city-registry.ts) и списки покрытия
(`COVERAGE_GREEN/YELLOW_CITIES`, trade_in.py) — одно множество, записанное в
двух местах. Они разошлись в обе стороны:

  предлагали, но не отвечали:  Серов
  отвечали, но не предлагали:  Берёзовский, Среднеуральск, Ревда

Житель Серова выбирал СВОЙ город из НАШЕГО дропдауна и получал:

  «Этот адрес вне области, по которой мы собираем данные.
   Сейчас это Свердловская область: Екатеринбург целиком и ещё несколько
   городов вокруг.»

Про город в той же самой области. Серов при этом покрыт данными: 363 активных
объявления в радиусе 15 км, все свежие (замер по проде). Поэтому добавлен в
жёлтый тир, а не убран из дропдаунa; три недостающих города добавлены на фронт.

Шапка city-registry.ts этот риск прямо предсказывала — «перед добавлением
7-го города сверить оба списка вручную, теста на это пока нет». Теперь тест
есть: бэкендовый сьют читает TS-реестр и требует РАВЕНСТВА множеств. Плюс
проверка, что у каждого города с порогом есть центроид, — иначе порог мёртвый,
город по координатам не резолвится.

## 2. Подсказки не слушались выбранного города

`city_hint` доезжает до геокодера, но на выдачу не влияет: его смотрит только
екатеринбургский кадастровый тир (как признак «речь не про ЕКБ, тир
пропускаем»), а DaData-тир ограничен регионом целиком и хинта не принимает.

Замер: выбран Серов, введено «Ленина 1» → первой подсказкой «Невьянский р-н,
пгт Верх-Нейвинский». Человек выбирает верхний вариант и считает чужой дом —
ровно баг #2576, ради которого город и спрашивают.

Публичная ручка теперь подставляет город в саму строку запроса. Проверено на
проде: «Серов Ленина 1» даёт серовскую выдачу целиком. Для Екатеринбурга
подстановка безвредна — три разных адреса дали тот же результат с префиксом и
без, поэтому правило одно на все города, без исключения для основного трафика.

Чинится в публичной ручке, а не в геокодере: там от `city_hint` зависит
поведение закрытого контура (`target_city_ambiguous`).

## Фикстура теста

`_FAR_AWAY_CITY` стояла в 21 км от центра Серова и работала как «далеко от
всех» лишь потому, что Серов не был поддержан. Переехала в Тавду — 271 км до
ближайшего центроида.

## Мутации

  убрать Серов из покрытия (состояние прода) → падает сверка списков
  не подставлять город в строку             → падает проверка ручки
  откат                                     → 21 passed

Плюс backend 75 passed, vitest 56 passed, tsc, lint, build, isolation guard.

`city-registry.ts` добавлен в paths-фильтр БЭКЕНДОВОГО лэйна: сверку списков
делает бэкендовый тест, и без этой строки правка одного лишь дропдауна её бы
не запускала — то есть ровно тот путь, которым списки и разошлись.
lekss361 merged commit b474a5f44e into main 2026-08-16 10:09:14 +00:00
lekss361 deleted branch fix/mera-city-parity 2026-08-16 10:09:14 +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#2919
No description provided.