fix(ptica): два блока analyze_parcel глотали ошибку БД без SAVEPOINT (#2464) #2949

Merged
bot-backend merged 1 commit from fix/2464-parcels-savepoint-pair into main 2026-08-20 07:19:50 +00:00
Collaborator

Правило записано в этой же функции — и дважды нарушено

В analyze_parcel двенадцать соседних блоков оборачивают свой db.execute в db.begin_nested(). У velocity-блока правило сформулировано словами:

«SAVEPOINT защищает outer transaction если velocity SQL падает — иначе следующие queries (_geotech_risk и пр.) крашатся с InFailedSqlTransaction»

Два блока из правила выпадали:

место ближайший честный сосед
get_permits_nearby (:3752) блок разрешений 10d-pre2 (:3687) — 60 строк выше, та же функция
_neighbors_summary (:927) те же двенадцать блоков файла

get_permits_nearby делает db.execute на переданной сессии и своей защиты не имеет — глотает вызывающий.

Радиус поражения

После незащищённого блока разрешений идут:

:4141  _geotech_risk(66, db, geom_wkt)
:4145  _neighbors_summary(db, geom_wkt, cad_num)
~:4220 persist_analysis_run

Один упавший запрос к gisogd_permits оставлял транзакцию в aborted-состоянии и уносил весь анализ, а не блок разрешений. У _neighbors_summary жертвой становилась запись прогона.

Тест — на двойнике с настоящей семантикой Postgres

Использован tests/support/pg_session.py из #2938: обычный MagicMock не имеет aborted-состояния, и проверка «сессия осталась рабочей» на нём зелена независимо от наличия SAVEPOINT.

На origin/main:

AbortedTransactionError: current transaction is aborted, commands ignored until end of transaction block

Плюс контроль на сам двойник (без SAVEPOINT он обязан отравляться) и контроль на здоровый путь.

Честно про покрытие

Прямой тест есть только на _neighbors_summary — это отдельная функция, её можно вызвать. Блок get_permits_nearby лежит внутри обработчика, дотянуться можно лишь через полный эндпоинт с двойником, умеющим отвечать на десятки разных запросов.

Первая версия файла «покрывала» его так: тест сам писал with db.begin_nested(): вокруг вызова и проверял, что сессия выжила. Такая проверка зелена независимо от боевого кода — она проверяет собственную обёртку. Тест удалён, ограничение записано в шапке файла.

Лучше честно отсутствующее покрытие, чем поддельное. Правка там та же самая и по тому же доводу, но подтверждена чтением, а не тестом.

pytest tests/api/v1: 357 passed, 1 skipped, rc=0

Refs #2464

## Правило записано в этой же функции — и дважды нарушено В `analyze_parcel` двенадцать соседних блоков оборачивают свой `db.execute` в `db.begin_nested()`. У velocity-блока правило сформулировано словами: > «SAVEPOINT защищает outer transaction если velocity SQL падает — иначе следующие queries (`_geotech_risk` и пр.) крашатся с `InFailedSqlTransaction`» Два блока из правила выпадали: | место | ближайший честный сосед | |---|---| | `get_permits_nearby` (:3752) | блок разрешений 10d-pre2 (:3687) — **60 строк выше, та же функция** | | `_neighbors_summary` (:927) | те же двенадцать блоков файла | `get_permits_nearby` делает `db.execute` на переданной сессии и своей защиты не имеет — глотает вызывающий. ## Радиус поражения После незащищённого блока разрешений идут: ``` :4141 _geotech_risk(66, db, geom_wkt) :4145 _neighbors_summary(db, geom_wkt, cad_num) ~:4220 persist_analysis_run ``` Один упавший запрос к `gisogd_permits` оставлял транзакцию в aborted-состоянии и уносил **весь** анализ, а не блок разрешений. У `_neighbors_summary` жертвой становилась запись прогона. ## Тест — на двойнике с настоящей семантикой Postgres Использован `tests/support/pg_session.py` из #2938: обычный `MagicMock` не имеет aborted-состояния, и проверка «сессия осталась рабочей» на нём зелена **независимо** от наличия SAVEPOINT. На `origin/main`: ``` AbortedTransactionError: current transaction is aborted, commands ignored until end of transaction block ``` Плюс контроль на сам двойник (без SAVEPOINT он обязан отравляться) и контроль на здоровый путь. ## Честно про покрытие Прямой тест есть **только** на `_neighbors_summary` — это отдельная функция, её можно вызвать. Блок `get_permits_nearby` лежит внутри обработчика, дотянуться можно лишь через полный эндпоинт с двойником, умеющим отвечать на десятки разных запросов. Первая версия файла «покрывала» его так: тест **сам** писал `with db.begin_nested():` вокруг вызова и проверял, что сессия выжила. Такая проверка зелена независимо от боевого кода — она проверяет собственную обёртку. Тест удалён, ограничение записано в шапке файла. Лучше честно отсутствующее покрытие, чем поддельное. Правка там та же самая и по тому же доводу, но подтверждена чтением, а не тестом. `pytest tests/api/v1`: **357 passed, 1 skipped, rc=0** Refs #2464
bot-backend added 1 commit 2026-08-20 06:59:10 +00:00
fix(ptica): два блока analyze_parcel глотали ошибку БД без SAVEPOINT (#2464)
All checks were successful
CI / changes (pull_request) Successful in 10s
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m41s
CI / backend-tests (pull_request) Successful in 17m29s
b9381e15e0
Найдено поиском «правило соблюдено рядом — нарушено здесь». В самой функции
analyze_parcel двенадцать соседних блоков оборачивают свой db.execute в
db.begin_nested(), и у velocity-блока правило записано словами:

    «SAVEPOINT защищает outer transaction если velocity SQL падает — иначе
     следующие queries (_geotech_risk и пр.) крашатся с InFailedSqlTransaction»

Два блока из правила выпадали:

1. get_permits_nearby — вызов на общей сессии, своей защиты не имеет, ошибку
   глотает вызывающий. Разрыв с ближайшим честным соседом — 60 строк в ОДНОЙ
   функции.
2. _neighbors_summary — тот же класс, вызывается перед записью прогона.

Радиус поражения проверен по коду: после незащищённого блока разрешений идут
_geotech_risk (:4141), _neighbors_summary (:4145) и persist_analysis_run (~:4220).
Один упавший запрос к gisogd_permits оставлял транзакцию в aborted-состоянии и
уносил ВЕСЬ анализ, а не блок разрешений.

Тест использует двойник сессии из #2938 (tests/support/pg_session.py) —
MagicMock aborted-состояния не имеет, и на нём проверка «сессия осталась рабочей»
зелена независимо от наличия SAVEPOINT. Красный на origin/main:
`AbortedTransactionError: current transaction is aborted`.

ЧЕСТНО ПРО ПОКРЫТИЕ: прямой тест есть только на _neighbors_summary — это отдельная
функция. Блок get_permits_nearby лежит внутри обработчика, дотянуться можно лишь
через полный эндпоинт. Первая версия файла «покрывала» его тестом, который САМ
писал `with db.begin_nested():` вокруг вызова и проверял собственную обёртку —
такая проверка зелена независимо от боевого кода. Тест удалён, ограничение
записано в шапке: лучше честно отсутствующее покрытие, чем поддельное.

pytest tests/api/v1: 357 passed, 1 skipped, rc=0
bot-backend merged commit 38163a1186 into main 2026-08-20 07:19:50 +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#2949
No description provided.