(high) search.py/search_query.py: кадастровый номер всегда NULL в выдаче поиска — рассинхрон имён cadastral_number vs kadastr_num #1514

Closed
opened 2026-06-15 05:59:03 +00:00 by bot-backend · 1 comment
Collaborator

Severity: high · Категория: data-integrity · Файл: tradein-mvp/backend/app/api/v1/search.py:48

search_query.py:114 — SELECT тянет колонку cadastral_number из listings_search_mv, а схема SearchResultItem (search_response.py:27) объявляет поле kadastr_num: str | None = None без Field(alias=...). model_config = ConfigDict(from_attributes=True) без populate_by_name/alias_generator. В search.py:48 строки маппятся через SearchResultItem.model_validate(dict(r)): ключ dict — cadastral_number, поле модели — kadastr_num, совпадения нет, значение игнорируется (Pydantic v2 extra=ignore). Импакт: кадастровый номер у ВСЕХ listings в выдаче поиска всегда None — фича теряется молча. Чинить: либо переименовать поле схемы в cadastral_number, либо добавить Field(validation_alias='cadastral_number') (с populate_by_name при необходимости), либо алиасить колонку в SQL: cadastral_number AS kadastr_num. Тест test_search_api.py не ловит — проверяет только SQL и hand-crafted cache payload.

Почему баг: Миграция 094_cadastral_unify.sql переименовала kadastr_num → cadastral_number во всей схеме и пересоздала listings_search_mv так, что она экспонирует l.cadastral_number (094_cadastral_unify.sql:169). search_query.py:116 селектит cadastral_number, но search_response.py:27 всё ещё хранит старое имя kadastr_num: str | None = None без Field(alias=...). Ключи строки -> cadastral_number, поле модели -> kadastr_num: совпадения нет, значение никогда не подставляется. Тест test_search_api.py не ловит это, т.к. проверяет только build SQL и hand-crafted cache payload.

Как чинить: Переименовать поле схемы в cadastral_number: str | None = None ИЛИ добавить alias: kadastr_num: str | None = Field(default=None, validation_alias='cadastral_number') (плюс ConfigDict(populate_by_name=True)). Согласовать с фронтом.


deep-audit «армия ботов 2» · verify+harden, confidence 0.95 · unit U120

**Severity:** high · **Категория:** data-integrity · **Файл:** `tradein-mvp/backend/app/api/v1/search.py:48` search_query.py:114 — SELECT тянет колонку `cadastral_number` из listings_search_mv, а схема SearchResultItem (search_response.py:27) объявляет поле `kadastr_num: str | None = None` без Field(alias=...). model_config = ConfigDict(from_attributes=True) без populate_by_name/alias_generator. В search.py:48 строки маппятся через SearchResultItem.model_validate(dict(r)): ключ dict — `cadastral_number`, поле модели — `kadastr_num`, совпадения нет, значение игнорируется (Pydantic v2 extra=ignore). Импакт: кадастровый номер у ВСЕХ listings в выдаче поиска всегда None — фича теряется молча. Чинить: либо переименовать поле схемы в `cadastral_number`, либо добавить Field(validation_alias='cadastral_number') (с populate_by_name при необходимости), либо алиасить колонку в SQL: `cadastral_number AS kadastr_num`. Тест test_search_api.py не ловит — проверяет только SQL и hand-crafted cache payload. **Почему баг:** Миграция 094_cadastral_unify.sql переименовала kadastr_num → cadastral_number во всей схеме и пересоздала listings_search_mv так, что она экспонирует `l.cadastral_number` (094_cadastral_unify.sql:169). search_query.py:116 селектит `cadastral_number`, но search_response.py:27 всё ещё хранит старое имя `kadastr_num: str | None = None` без Field(alias=...). Ключи строки -> `cadastral_number`, поле модели -> `kadastr_num`: совпадения нет, значение никогда не подставляется. Тест test_search_api.py не ловит это, т.к. проверяет только build SQL и hand-crafted cache payload. **Как чинить:** Переименовать поле схемы в `cadastral_number: str | None = None` ИЛИ добавить alias: `kadastr_num: str | None = Field(default=None, validation_alias='cadastral_number')` (плюс ConfigDict(populate_by_name=True)). Согласовать с фронтом. --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.95 · unit U120</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:59:03 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:02:16 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода:

  • tradein-mvp/backend/app/services/search_query.py:114 — SELECT тянет колонку cadastral_number (и WHERE на ней :87).
  • tradein-mvp/backend/app/schemas/search_response.py:27 — поле модели kadastr_num: str | None = None, без Field(validation_alias=...).
  • search_response.py:11model_config = ConfigDict(from_attributes=True) — нет populate_by_name/alias_generator.
  • tradein-mvp/backend/app/api/v1/search.py:48SearchResultItem.model_validate(dict(r)).

Корень: ключ строки dict(r) = cadastral_number, поле модели = kadastr_num; имена не совпадают, alias не задан → Pydantic v2 игнорирует extra-ключ → kadastr_num всегда None в выдаче поиска. (Подтверждается, что 094_cadastral_unify переименовала схему/MV на cadastral_number, а response-схема осталась на старом имени.)

Что править:

  • Вариант A (рекомендуемый): переименовать поле в cadastral_number: str | None = None (согласовать с фронтом/openapi codegen).
  • Вариант B: kadastr_num: str | None = Field(default=None, validation_alias="cadastral_number") + ConfigDict(populate_by_name=True).
  • Вариант C (минимальный): алиас в SQL — cadastral_number AS kadastr_num в search_query.py:114.

Что посмотреть:

  • Код: search_response.py:10-28, search_query.py:87,114, search.py:48; добавить regression-тест в tradein-mvp/backend/tests/test_search_api.py, который мокает row с cadastral_number и проверяет, что значение доезжает в ответ (текущий тест проверяет только build-SQL и hand-crafted cache payload).
  • Vault: релевантных заметок не найдено (есть только общий old/decisions/MultiSource_Integration_Master_Plan.md про search-store, без этого бага).
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** - `tradein-mvp/backend/app/services/search_query.py:114` — SELECT тянет колонку `cadastral_number` (и WHERE на ней `:87`). - `tradein-mvp/backend/app/schemas/search_response.py:27` — поле модели `kadastr_num: str | None = None`, **без** `Field(validation_alias=...)`. - `search_response.py:11` — `model_config = ConfigDict(from_attributes=True)` — нет `populate_by_name`/`alias_generator`. - `tradein-mvp/backend/app/api/v1/search.py:48` — `SearchResultItem.model_validate(dict(r))`. **Корень:** ключ строки `dict(r)` = `cadastral_number`, поле модели = `kadastr_num`; имена не совпадают, alias не задан → Pydantic v2 игнорирует extra-ключ → `kadastr_num` всегда `None` в выдаче поиска. (Подтверждается, что `094_cadastral_unify` переименовала схему/MV на `cadastral_number`, а response-схема осталась на старом имени.) **Что править:** - Вариант A (рекомендуемый): переименовать поле в `cadastral_number: str | None = None` (согласовать с фронтом/openapi codegen). - Вариант B: `kadastr_num: str | None = Field(default=None, validation_alias="cadastral_number")` + `ConfigDict(populate_by_name=True)`. - Вариант C (минимальный): алиас в SQL — `cadastral_number AS kadastr_num` в `search_query.py:114`. **Что посмотреть:** - Код: `search_response.py:10-28`, `search_query.py:87,114`, `search.py:48`; добавить regression-тест в `tradein-mvp/backend/tests/test_search_api.py`, который мокает row с `cadastral_number` и проверяет, что значение доезжает в ответ (текущий тест проверяет только build-SQL и hand-crafted cache payload). - Vault: релевантных заметок не найдено (есть только общий `old/decisions/MultiSource_Integration_Master_Plan.md` про search-store, без этого бага).
Sign in to join this conversation.
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#1514
No description provided.