[opportunity_harvest] n_features инкрементится до per-quarter commit — отчёт завышает число persisted фич при сбое commit #1624

Closed
opened 2026-06-16 17:21:55 +00:00 by bot-backend · 0 comments
Collaborator

Severity: low · Категория: logic/reporting · Файл: backend/app/workers/tasks/opportunity_harvest.py:89-107

Файл: backend/app/workers/tasks/opportunity_harvest.py:89-107. n_features += 1 выполняется при каждом успешном _upsert_feature (строки 89-97), ДО per-quarter db.commit() (строка 100). Если db.commit() на строке 100 бросит исключение (deadlock, обрыв соединения, statement timeout в конце длинного grid-walk), управление уходит в except (строки 101-104), который делает db.rollback() — откатывая все незакоммиченные UPSERT'ы этого квартала. Но n_features уже учёл эти фичи и не уменьшается. Аналогично n_quarters += 1 (строка 73) инкрементится до завершения записи квартала.

Импакт: возвращаемый отчёт {'quarters': N, 'features': M} в сценарии отказа commit завышает число фактически persisted opportunity-фич — «ложь в отчёте». Срабатывает только при отказе самого commit (узкий путь); per-row ошибки уже изолированы SAVEPOINT'ом внутри _upsert_feature (ON CONFLICT, SAVEPOINT per-row) и в этот класс не попадают. Severity low.

Фикс: считать n_features в локальную per-quarter переменную и прибавлять к итогу только ПОСЛЕ успешного db.commit(); при except — не учитывать. Аналогично n_quarters инкрементить после успешного commit квартала.

Почему баг: Возвращаемый отчёт {'features': M} в этом сценарии завышает число фактически persisted opportunity-фич: счётчик включает откатанные строки квартала, чей commit упал. Это «ложь в отчёте» о числе записей. Срабатывает только при отказе commit (узкий путь), per-row ошибки уже изолированы SAVEPOINT'ом и в этот класс не попадают — поэтому low. Аналогично n_quarters (строка 73) учитывает квартал до завершения его записи.

Как чинить: Считать фичи в локальный per-quarter счётчик и прибавлять к n_features ТОЛЬКО после успешного db.commit() квартала; при откате — не прибавлять (или вычитать). Тогда возвращаемый features всегда соответствует закоммиченному.


deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.85 · unit B45

**Severity:** low · **Категория:** logic/reporting · **Файл:** `backend/app/workers/tasks/opportunity_harvest.py:89-107` Файл: backend/app/workers/tasks/opportunity_harvest.py:89-107. n_features += 1 выполняется при каждом успешном _upsert_feature (строки 89-97), ДО per-quarter db.commit() (строка 100). Если db.commit() на строке 100 бросит исключение (deadlock, обрыв соединения, statement timeout в конце длинного grid-walk), управление уходит в except (строки 101-104), который делает db.rollback() — откатывая все незакоммиченные UPSERT'ы этого квартала. Но n_features уже учёл эти фичи и не уменьшается. Аналогично n_quarters += 1 (строка 73) инкрементится до завершения записи квартала. Импакт: возвращаемый отчёт {'quarters': N, 'features': M} в сценарии отказа commit завышает число фактически persisted opportunity-фич — «ложь в отчёте». Срабатывает только при отказе самого commit (узкий путь); per-row ошибки уже изолированы SAVEPOINT'ом внутри _upsert_feature (ON CONFLICT, SAVEPOINT per-row) и в этот класс не попадают. Severity low. Фикс: считать n_features в локальную per-quarter переменную и прибавлять к итогу только ПОСЛЕ успешного db.commit(); при except — не учитывать. Аналогично n_quarters инкрементить после успешного commit квартала. **Почему баг:** Возвращаемый отчёт {'features': M} в этом сценарии завышает число фактически persisted opportunity-фич: счётчик включает откатанные строки квартала, чей commit упал. Это «ложь в отчёте» о числе записей. Срабатывает только при отказе commit (узкий путь), per-row ошибки уже изолированы SAVEPOINT'ом и в этот класс не попадают — поэтому low. Аналогично n_quarters (строка 73) учитывает квартал до завершения его записи. **Как чинить:** Считать фичи в локальный per-quarter счётчик и прибавлять к n_features ТОЛЬКО после успешного db.commit() квартала; при откате — не прибавлять (или вычитать). Тогда возвращаемый features всегда соответствует закоммиченному. --- <sub>deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.85 · unit B45</sub>
bot-backend added the
week ревью 1
label 2026-06-16 17:21:55 +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#1624
No description provided.