fix(ptica): шесть lookup'ов /analyze глотали ошибку БД без SAVEPOINT (#2464) #2951

Merged
bot-backend merged 1 commit from fix/2464-ird-lookups-savepoint into main 2026-08-20 07:38:24 +00:00
Collaborator

Что не так

Шесть функций в site_finder работают на общей с analyze_parcel сессии и глотают (OperationalError, ProgrammingError) вокруг db.execute, не открыв SAVEPOINT.

В Postgres проглоченная ошибка не исчезает: транзакция остаётся в aborted-состоянии, и падает следующий запрос — в другом месте отчёта и с другой причиной в логе. Сам lookup при этом отчитывается «пусто, штатно».

Как нашёл

Соседний ppt_tep_lookup — та же семья, та же таблица planning_projects — SAVEPOINT имеет. Пересчёт по всей семье:

ppt_tep_lookup           begin_nested=1  db.execute=1   ← эталон
planning_lookup          begin_nested=0  db.execute=1
granddoc_lookup          begin_nested=0  db.execute=1
ird_overlay_lookup       begin_nested=0  db.execute=1
functional_zone_lookup   begin_nested=0  db.execute=1
reservation_lookup       begin_nested=0  db.execute=1
zone_regulation          begin_nested=1  db.execute=2   ← upsert защищён, SELECT нет

Проверка — двусторонняя

tests/services/site_finder/test_2464_ird_lookups_savepoint.py параметризован по всем шести именам, плюс два контроля.

На origin/main:

6 failed  — AbortedTransactionError
2 passed  — контроли

Красное здесь означает «неверное поведение», а не «символа нет»: тест ловит именно отравленную сессию через PostgresLikeSession (tests/support/pg_session.py, #2938), у MagicMock aborted-состояния нет и тест был бы зелёным по построению.

Контроли:

  • без SAVEPOINT сессия травится — падает, если убрать защиту (мутационная проверка: тест умеет краснеть);
  • здоровый путь по-прежнему читает строки — правка не сломала штатное чтение.

Про no-op в стабах

После правки 28 существующих тестов упали на AttributeError: '_FakeDB' object has no attribute 'begin_nested'. Стабы в пяти файлах получили no-op @contextmanager begin_nested. В шапке каждого написано, где SAVEPOINT проверяется по-настоящему — чтобы no-op не читался как покрытие: сам по себе он ничего не гарантирует.

Прогоны

tests/services   3097 passed, 14 skipped   rc=0
tests/api/v1      362 passed,  1 skipped   rc=0

Часть эпика #2464.

## Что не так Шесть функций в `site_finder` работают на **общей** с `analyze_parcel` сессии и глотают `(OperationalError, ProgrammingError)` вокруг `db.execute`, не открыв SAVEPOINT. В Postgres проглоченная ошибка не исчезает: транзакция остаётся в aborted-состоянии, и падает **следующий** запрос — в другом месте отчёта и с другой причиной в логе. Сам lookup при этом отчитывается «пусто, штатно». ## Как нашёл Соседний `ppt_tep_lookup` — та же семья, та же таблица `planning_projects` — SAVEPOINT имеет. Пересчёт по всей семье: ``` ppt_tep_lookup begin_nested=1 db.execute=1 ← эталон planning_lookup begin_nested=0 db.execute=1 granddoc_lookup begin_nested=0 db.execute=1 ird_overlay_lookup begin_nested=0 db.execute=1 functional_zone_lookup begin_nested=0 db.execute=1 reservation_lookup begin_nested=0 db.execute=1 zone_regulation begin_nested=1 db.execute=2 ← upsert защищён, SELECT нет ``` ## Проверка — двусторонняя `tests/services/site_finder/test_2464_ird_lookups_savepoint.py` параметризован по всем шести именам, плюс два контроля. На `origin/main`: ``` 6 failed — AbortedTransactionError 2 passed — контроли ``` Красное здесь означает «неверное поведение», а не «символа нет»: тест ловит именно отравленную сессию через `PostgresLikeSession` (`tests/support/pg_session.py`, #2938), у `MagicMock` aborted-состояния нет и тест был бы зелёным по построению. Контроли: - **без SAVEPOINT сессия травится** — падает, если убрать защиту (мутационная проверка: тест умеет краснеть); - **здоровый путь по-прежнему читает строки** — правка не сломала штатное чтение. ## Про no-op в стабах После правки 28 существующих тестов упали на `AttributeError: '_FakeDB' object has no attribute 'begin_nested'`. Стабы в пяти файлах получили no-op `@contextmanager begin_nested`. В шапке каждого написано, где SAVEPOINT проверяется **по-настоящему** — чтобы no-op не читался как покрытие: сам по себе он ничего не гарантирует. ## Прогоны ``` tests/services 3097 passed, 14 skipped rc=0 tests/api/v1 362 passed, 1 skipped rc=0 ``` Часть эпика #2464.
bot-backend added 1 commit 2026-08-20 07:19:31 +00:00
fix(ptica): шесть lookup'ов /analyze глотали ошибку БД без SAVEPOINT (#2464)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
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 / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m31s
CI / backend-tests (pull_request) Successful in 17m27s
7cde3b8eaa
Шесть функций в site_finder работают на ОБЩЕЙ с analyze_parcel сессии и
глотают (OperationalError, ProgrammingError) вокруг db.execute. Без SAVEPOINT
проглоченная ошибка оставляет транзакцию в aborted-состоянии: сам lookup
возвращает пустой результат «штатно», а падает следующий за ним запрос —
в другом месте отчёта и с другой причиной в логе.

Соседний ppt_tep_lookup — та же семья, та же таблица planning_projects —
SAVEPOINT имел. Правка сводит шесть отставших к нему:

  planning_lookup, granddoc_lookup, ird_overlay_lookup,
  functional_zone_lookup, reservation_lookup  — по одному db.execute
  zone_regulation                             — upsert был защищён, SELECT нет

Тест параметризован по всем шести именам, плюс два контроля: «без SAVEPOINT
сессия травится» и «здоровый путь по-прежнему читает строки». На origin/main
шесть падают с AbortedTransactionError, оба контроля зелёные.

Стабы _FakeDB/_DB в пяти существующих тестах получили no-op begin_nested —
без него 28 тестов падали на AttributeError. В шапке каждого стаба указано,
где SAVEPOINT проверяется по-настоящему, чтобы no-op не читался как покрытие.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bot-backend merged commit c93d6cbde1 into main 2026-08-20 07:38:24 +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#2951
No description provided.