fix(site_finder): SAVEPOINT supply/market + convert 2 bare rollbacks (#2464 Wave 2) #2469

Merged
bot-backend merged 1 commit from worktree-agent-adde7f2e3fd46a2cb into main 2026-07-08 06:46:10 +00:00
Collaborator

Что

Волна 2 эпика #2464, часть 3/3 — supply/market (11 сайтов в 5 файлах), включая 2 конверсии bare db.rollback() → savepoint (хуже swallow'а: голый rollback на shared per-request сессии сбрасывает ВСЮ незакоммиченную работу запроса и orphan'ит outer SessionTransaction).

swallow → savepoint

  • market_metrics.py: _query_stock, _query_sales_window (critical), _price_sensitivity (savepoint вокруг непрямого _elasticity_coef, где реально db.execute), compute_offer_price_trend
  • best_layouts.py: Step-5 supply batch query
  • future_supply.py: _query_supply_rows
  • own_portfolio.py: _query_current, _query_future
  • custom_pois.py: get_overlaps_for_scoring

bare-rollback → savepoint (поведенчески-чувствительно)

  • best_layouts.py _fetch_supply_only_layouts — single execute: обёрнут в begin_nested, голый rollback убран, фолбэк [] неизменен.
  • best_layouts.py Step 2b core-attribution — три db.execute вперемешку с pure-Python (_merged_project_name_pool, match_groups_to_projects — проверено: без DB-I/O) → whole-body savepoint (all-or-nothing, ровно старая семантика bare-rollback-everything); фолбэк core_group_to_project = {} неизменен.

Сессия best_layouts — своя per-request (POST /{cad}/best-layoutsDepends(get_db) → threadpool), прогоняется через 6+ последовательных шагов, поэтому баг-класс тот же (прецедент velocity.py:170). Ноль исполняемых db.rollback() осталось в 5 файлах (только комментарии). Фолбэки и типы except байт-в-байт неизменны.

Тесты

Триада на каждый сайт (savepoint-used / graceful-fallback / session-usable-after-failure); для 2 ex-rollback-сайтов + offer-trend дополнительно db.rollback.assert_not_called(). 280 тестов затронутых сьютов зелёные, pinned ruff 0.7.4 чисто.

Ревью

code-reviewer: APPROVE, ноль блокеров. Независимо подтверждены: shared-сессия best_layouts, атомарность whole-body savepoint (pure-Python хелперы без DB), _elasticity_coef пропагирует (savepoint на верном уровне), отсутствие исполняемых rollback/:x::type/tradein, покрытие тестами. Один pre-existing ruff-drift (future_supply.py E302) — не из этого диффа.

Refs #2464 (cluster A, Wave 2 · 3/3).

## Что Волна 2 эпика **#2464**, часть 3/3 — supply/market (11 сайтов в 5 файлах), включая **2 конверсии bare `db.rollback()` → savepoint** (хуже swallow'а: голый rollback на shared per-request сессии сбрасывает ВСЮ незакоммиченную работу запроса и orphan'ит outer SessionTransaction). ### swallow → savepoint - `market_metrics.py`: `_query_stock`, `_query_sales_window` (**critical**), `_price_sensitivity` (savepoint вокруг непрямого `_elasticity_coef`, где реально `db.execute`), `compute_offer_price_trend` - `best_layouts.py`: Step-5 supply batch query - `future_supply.py`: `_query_supply_rows` - `own_portfolio.py`: `_query_current`, `_query_future` - `custom_pois.py`: `get_overlaps_for_scoring` ### bare-rollback → savepoint (поведенчески-чувствительно) - `best_layouts.py` `_fetch_supply_only_layouts` — single execute: обёрнут в `begin_nested`, голый rollback убран, фолбэк `[]` неизменен. - `best_layouts.py` Step 2b core-attribution — **три** `db.execute` вперемешку с pure-Python (`_merged_project_name_pool`, `match_groups_to_projects` — проверено: без DB-I/O) → **whole-body savepoint** (all-or-nothing, ровно старая семантика bare-rollback-everything); фолбэк `core_group_to_project = {}` неизменен. Сессия `best_layouts` — своя per-request (`POST /{cad}/best-layouts` → `Depends(get_db)` → threadpool), прогоняется через 6+ последовательных шагов, поэтому баг-класс тот же (прецедент `velocity.py:170`). Ноль исполняемых `db.rollback()` осталось в 5 файлах (только комментарии). Фолбэки и типы `except` байт-в-байт неизменны. ## Тесты Триада на каждый сайт (savepoint-used / graceful-fallback / session-usable-after-failure); для 2 ex-rollback-сайтов + offer-trend дополнительно `db.rollback.assert_not_called()`. 280 тестов затронутых сьютов зелёные, pinned ruff 0.7.4 чисто. ## Ревью code-reviewer: **✅ APPROVE**, ноль блокеров. Независимо подтверждены: shared-сессия best_layouts, атомарность whole-body savepoint (pure-Python хелперы без DB), `_elasticity_coef` пропагирует (savepoint на верном уровне), отсутствие исполняемых rollback/`:x::type`/tradein, покрытие тестами. Один pre-existing ruff-drift (`future_supply.py` E302) — не из этого диффа. Refs #2464 (cluster A, Wave 2 · 3/3).
bot-backend added 1 commit 2026-07-08 06:30:10 +00:00
fix(site_finder): SAVEPOINT-isolate supply/market db.execute + kill 2 bare rollbacks (#2464)
All checks were successful
CI / changes (pull_request) Successful in 9s
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-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 2m41s
CI / backend-tests (pull_request) Successful in 15m25s
73739671a9
Convert two bare db.rollback() calls on the shared per-request session
(best_layouts _fetch_supply_only_layouts + Step 2b core-attribution) to
db.begin_nested() — a bare rollback there discards ALL uncommitted work of
the request and orphans the outer SessionTransaction. Also wrap the swallow
sites in market_metrics (_query_stock, _query_sales_window, _price_sensitivity,
compute_offer_price_trend), best_layouts step-5 supply, future_supply
_query_supply_rows, own_portfolio _query_current/_query_future, and
custom_pois get_overlaps_for_scoring so a failed statement no longer poisons
the shared tx for later steps. Per-site regression tests assert fallback
preserved, begin_nested used, bare rollback NOT called, and session usable
after failure.

Refs #2464 (cluster A session-poisoning, Wave 2).
EOF2
echo "HANDLED"
bot-backend merged commit d3f3370bed into main 2026-07-08 06:46:10 +00:00
bot-backend deleted branch worktree-agent-adde7f2e3fd46a2cb 2026-07-08 06:46:11 +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#2469
No description provided.