[Fable 5][P2] GET /{cad}/isochrones и /{cad}/poi-score: 500 (float(None)) для участков с NULL-геометрией — нет фильтра geom IS NOT NULL #1201

Closed
opened 2026-06-13 04:49:42 +00:00 by bot-backend · 0 comments
Collaborator

Из армейского ревью Claude Fable 5 (2026-06-11)

Confirmed by 2/2 адверсариальных верификатора, severity P2 (correctness), confidence 0.85.

Файл

backend/app/api/v1/parcels.py:3090

Evidence (цитата кода)

              FROM (
                SELECT geom FROM cad_quarters_geom WHERE cad_number = :c
                UNION ALL
                SELECT geom FROM cad_buildings WHERE cad_num = :c
                UNION ALL
                SELECT geom FROM cad_parcels_geom WHERE cad_num = :c
              ) g
             LIMIT 1

Why bug

cad_parcels_geom — теперь VIEW над cad_parcels (93_*.sql), где geom nullable; в analyze (строки 1504-1507 этого же файла) задокументировано 964 прод-строки с NULL geom и явно добавлен фильтр «geom IS NOT NULL во всех ветках... иначе ST_Centroid→NULL→float(None)→500». В get_isochrones (3086-3111) и get_poi_score (3182-3207) фильтра нет: для таких cad запрос вернёт строку с lat/lon=NULL, guard if not coord_row её пропустит (RowMapping truthy), и lat = float(coord_row["lat"]) упадёт TypeError → 500 вместо 404. NULL-строка в ранней UNION-ветке также затеняет валидную геометрию в поздней.

Suggested fix

Добавить AND geom IS NOT NULL во все три ветки UNION в обоих эндпоинтах (зеркало запроса в analyze, строки 1528-1542) и/или проверять coord_row["lat"] is None → 404.

Verify notes

  • [real/P2] Трасса: cad из 964 прод-строк cad_parcels с NULL geom (view из 93_*.sql не фильтрует) → UNION-подзапрос (3090-3094/3186-3190) вернёт строку lat/lon=NULL; RowMapping len=2 → truthy → guard if not coord_row не срабатывает → float(None) TypeError на 3110/3206 вне try → 500 вместо 404. Тот же файл в analyze (1483-1507) ставит geom IS NOT NULL во всех ветках и комментарием документирует именно этот краш. Поражены оба эндпоинта. P2: 500 на подмножестве прод-данных, без data-loss/security.
  • [real/P2] Защиты нет: VIEW cad_parcels_geom (92/93_*.sql) = bare SELECT FROM cad_parcels, где geom nullable; NULL-строки реальны (комментарий в analyze: 964 на проде). Guard if not coord_row не ловит RowMapping {lat:None,lon:None} (truthy) → float(None) → TypeError → 500 вместо 404. Все сиблинги (analyze:1483-1495, competitors, best_layouts, product_scoring) фильтруют geom IS NOT NULL — эти два эндпоинта единственное отклонение. Глобального exception-handler нет. P2 подтверждаю.

Provenance

  • Finders: api-core
  • Confidence: 0.85
  • Originally batched at: main@d796027
## Из армейского ревью Claude Fable 5 (2026-06-11) Confirmed by 2/2 адверсариальных верификатора, severity **P2** (correctness), confidence 0.85. ## Файл [`backend/app/api/v1/parcels.py:3090`](backend/app/api/v1/parcels.py:3090) ## Evidence (цитата кода) ``` FROM ( SELECT geom FROM cad_quarters_geom WHERE cad_number = :c UNION ALL SELECT geom FROM cad_buildings WHERE cad_num = :c UNION ALL SELECT geom FROM cad_parcels_geom WHERE cad_num = :c ) g LIMIT 1 ``` ## Why bug cad_parcels_geom — теперь VIEW над cad_parcels (93_*.sql), где geom nullable; в analyze (строки 1504-1507 этого же файла) задокументировано 964 прод-строки с NULL geom и явно добавлен фильтр «geom IS NOT NULL во всех ветках... иначе ST_Centroid→NULL→float(None)→500». В get_isochrones (3086-3111) и get_poi_score (3182-3207) фильтра нет: для таких cad запрос вернёт строку с lat/lon=NULL, guard `if not coord_row` её пропустит (RowMapping truthy), и `lat = float(coord_row["lat"])` упадёт TypeError → 500 вместо 404. NULL-строка в ранней UNION-ветке также затеняет валидную геометрию в поздней. ## Suggested fix Добавить `AND geom IS NOT NULL` во все три ветки UNION в обоих эндпоинтах (зеркало запроса в analyze, строки 1528-1542) и/или проверять `coord_row["lat"] is None` → 404. ## Verify notes - [real/P2] Трасса: cad из 964 прод-строк cad_parcels с NULL geom (view из 93_*.sql не фильтрует) → UNION-подзапрос (3090-3094/3186-3190) вернёт строку lat/lon=NULL; RowMapping len=2 → truthy → guard `if not coord_row` не срабатывает → float(None) TypeError на 3110/3206 вне try → 500 вместо 404. Тот же файл в analyze (1483-1507) ставит geom IS NOT NULL во всех ветках и комментарием документирует именно этот краш. Поражены оба эндпоинта. P2: 500 на подмножестве прод-данных, без data-loss/security. - [real/P2] Защиты нет: VIEW cad_parcels_geom (92/93_*.sql) = bare SELECT FROM cad_parcels, где geom nullable; NULL-строки реальны (комментарий в analyze: 964 на проде). Guard `if not coord_row` не ловит RowMapping {lat:None,lon:None} (truthy) → float(None) → TypeError → 500 вместо 404. Все сиблинги (analyze:1483-1495, competitors, best_layouts, product_scoring) фильтруют geom IS NOT NULL — эти два эндпоинта единственное отклонение. Глобального exception-handler нет. P2 подтверждаю. ## Provenance - Finders: `api-core` - Confidence: 0.85 - Originally batched at: main@d796027
bot-backend added the
Fable 5 ревью
label 2026-06-13 04:49:42 +00:00
Sign in to join this conversation.
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#1201
No description provided.