date_cr минует _parse_nspd_date → CAST(:date_cr AS date) роняет upsert_quarter_stats и весь harvest_quarter квартала (нет savepoint) #1628

Closed
opened 2026-06-16 18:44:20 +00:00 by bot-backend · 0 comments
Collaborator

Severity: high · Категория: crash / data-loss · Файл: backend/app/services/cadastre/bulk_harvest.py:1389,1426 (вызов без savepoint: 265-267)

bulk_harvest.py:1426 — "date_cr": raw_opts.get("date_cr") передаётся сырым из NSPD в CAST(:date_cr AS date) (bulk_harvest.py:1389). Это ЕДИНСТВЕННОЕ date-поле во всём файле, не проходящее через _parse_nspd_date; остальные нормализуются (registration_date :780/:898/:1028/:1152/:1258, build_record_registration_date :895, legal_act_date :1255). Реальные NSPD-форматы (см. docstring _parse_nspd_date bulk_harvest.py:1558-1562): '13.03.2023' (DD.MM.YYYY) → CAST падает InvalidDatetimeFormat (DateStyle), '' → invalid input syntax for type date, '2023-03-13 00:00:00' тоже не чистый date-литерал. Импакт: вызов upsert_quarter_stats в harvest_quarter (bulk_harvest.py:267) НЕ обёрнут в db.begin_nested() (savepoint :271-276 покрывает только geom auto-heal), поэтому DataError пробрасывается наверх, прерывает обработку квартала и оставляет сессию в aborted-transaction state. Достаточно одного date_cr='' или DD.MM.YYYY в feature CAT_QUARTER_STATS, чтобы квартал не досчитался. Фикс: обернуть бинд через _parse_nspd_date — "date_cr": _parse_nspd_date(raw_opts.get("date_cr")) (как у всех прочих date-полей). Доп. защита: обернуть вызов upsert_quarter_stats (:267) в db.begin_nested() аналогично geom auto-heal.

Почему баг: upsert_quarter_stats вызывается в harvest_quarter (строка 267) БЕЗ try/except и БЕЗ db.begin_nested() — savepoint есть только у geom auto-heal ниже (строки 271-276). Поэтому DataError из CAST(:date_cr) пробрасывается наверх, прерывает harvest_quarter этого квартала и переводит сессию в aborted-transaction state. Достаточно одного пустого date_cr='' или одной DD.MM.YYYY-даты в feature 36381, чтобы квартал не досчитался. Это регрессия консистентности: фикс _parse_nspd_date применён ко всем датам, кроме этой одной.

Как чинить: Обернуть в нормализатор: "date_cr": _parse_nspd_date(raw_opts.get("date_cr")) — как для остальных date-полей. Дополнительно желательно вызывать upsert_quarter_stats под db.begin_nested() в harvest_quarter.


deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.92 · unit B16

**Severity:** high · **Категория:** crash / data-loss · **Файл:** `backend/app/services/cadastre/bulk_harvest.py:1389,1426 (вызов без savepoint: 265-267)` bulk_harvest.py:1426 — "date_cr": raw_opts.get("date_cr") передаётся сырым из NSPD в CAST(:date_cr AS date) (bulk_harvest.py:1389). Это ЕДИНСТВЕННОЕ date-поле во всём файле, не проходящее через _parse_nspd_date; остальные нормализуются (registration_date :780/:898/:1028/:1152/:1258, build_record_registration_date :895, legal_act_date :1255). Реальные NSPD-форматы (см. docstring _parse_nspd_date bulk_harvest.py:1558-1562): '13.03.2023' (DD.MM.YYYY) → CAST падает InvalidDatetimeFormat (DateStyle), '' → invalid input syntax for type date, '2023-03-13 00:00:00' тоже не чистый date-литерал. Импакт: вызов upsert_quarter_stats в harvest_quarter (bulk_harvest.py:267) НЕ обёрнут в db.begin_nested() (savepoint :271-276 покрывает только geom auto-heal), поэтому DataError пробрасывается наверх, прерывает обработку квартала и оставляет сессию в aborted-transaction state. Достаточно одного date_cr='' или DD.MM.YYYY в feature CAT_QUARTER_STATS, чтобы квартал не досчитался. Фикс: обернуть бинд через _parse_nspd_date — "date_cr": _parse_nspd_date(raw_opts.get("date_cr")) (как у всех прочих date-полей). Доп. защита: обернуть вызов upsert_quarter_stats (:267) в db.begin_nested() аналогично geom auto-heal. **Почему баг:** upsert_quarter_stats вызывается в harvest_quarter (строка 267) БЕЗ try/except и БЕЗ db.begin_nested() — savepoint есть только у geom auto-heal ниже (строки 271-276). Поэтому DataError из CAST(:date_cr) пробрасывается наверх, прерывает harvest_quarter этого квартала и переводит сессию в aborted-transaction state. Достаточно одного пустого date_cr='' или одной DD.MM.YYYY-даты в feature 36381, чтобы квартал не досчитался. Это регрессия консистентности: фикс _parse_nspd_date применён ко всем датам, кроме этой одной. **Как чинить:** Обернуть в нормализатор: "date_cr": _parse_nspd_date(raw_opts.get("date_cr")) — как для остальных date-полей. Дополнительно желательно вызывать upsert_quarter_stats под db.begin_nested() в harvest_quarter. --- <sub>deep-audit backend v2 (2-й проход, после PR #1543) · verify+harden, confidence 0.92 · unit B16</sub>
bot-backend added the
week ревью 1
label 2026-06-16 18:44:20 +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#1628
No description provided.