[Fable 5][uncertain][P3] chat.py: async-хендлер /chat/ask выполняет синхронное чтение БД (JSONB-отчёт) в event loop'е #1245

Closed
opened 2026-06-13 04:58:12 +00:00 by bot-backend · 0 comments
Collaborator

Из армейского ревью Claude Fable 5 (2026-06-11) — UNCERTAIN (1/2 верификаторов real)

⚠️ Только 1 из 2 адверсариальных верификаторов подтвердил баг как real. Заведено по решению Anton (2026-06-13) — требует дополнительной проверки перед фиксом. Severity P3 (concurrency), confidence 0.6.

Файл

backend/app/api/v1/chat.py:66

Evidence (цитата кода)

    try:
        report, run_id = get_report_for_chat(db, payload.cad_num)

Why bug (по версии finder'а)

Хендлер объявлен async def ask, но get_report_for_chat ходит в БД синхронной SQLAlchemy-сессией и тянет крупный JSONB-блоб §22-отчёта — блокирует event loop на каждый запрос чата (LLM-ветка корректно мостится через run_in_threadpool, а это чтение — нет). Docstring ссылается «как get_parcel_forecast», но тот — sync def и исполняется в threadpool; locations.py/insights.py прямо предупреждают, что «async def + sync db.execute заблокировало бы loop». Под параллельной нагрузкой чата деградирует латентность всех эндпоинтов.

Suggested fix

Сделать хендлер sync def ask(...) (FastAPI уведёт в threadpool), либо обернуть get_report_for_chat в run_in_threadpool, как уже сделано для orchestrate_chat.

Verify notes (вердикты адверсариальных верификаторов)

  • [real/P3] Трассировка: async def ask (chat.py:53) на строке 66 синхронно зовёт get_report_for_chat → latest_run_for → db.execute(...).first() — блокирующий psycopg3 I/O, тянущий «тяжёлый result-блоб (~90 ключей JSONB)» (repository.py:234) в event loop'е. LLM-ветка мостится через run_in_threadpool (стр. 132), это чтение — нет; в det-ветке await'ов нет вовсе. locations.py:18/insights.py:19 документируют паттерн как блокирующий loop; get_parcel_forecast — sync def. P3: деградация латентности.
  • [refuted/P3] Механика верна, но это документированный house-style: backend.md требует «FastAPI handlers: async def»; ≥6 async-хендлеров (by-bbox — самый горячий, poi-score, competitors, best-layouts, PDF-рендер WeasyPrint) делают sync-БД/CPU в loop напрямую. Спорное чтение — индексированный SELECT LIMIT 1 (idx_analysis_runs_cad_created), миллисекунды; тяжёлая LLM-ветка мостится корректно. Деградация нереалистична при auth-gated low-traffic чате. Консистентность-рефакторинг, не дефект.

Provenance

  • Finders: api-core
  • Confidence: 0.6
  • Verifier votes: 1 real / 1 refuted (на основании 2 попыток)
  • Originally batched at: main@d796027
## Из армейского ревью Claude Fable 5 (2026-06-11) — UNCERTAIN (1/2 верификаторов real) ⚠️ **Только 1 из 2 адверсариальных верификаторов подтвердил баг как `real`**. Заведено по решению Anton (2026-06-13) — требует **дополнительной проверки** перед фиксом. Severity **P3** (concurrency), confidence 0.6. ## Файл [`backend/app/api/v1/chat.py:66`](backend/app/api/v1/chat.py:66) ## Evidence (цитата кода) ``` try: report, run_id = get_report_for_chat(db, payload.cad_num) ``` ## Why bug (по версии finder'а) Хендлер объявлен `async def ask`, но get_report_for_chat ходит в БД синхронной SQLAlchemy-сессией и тянет крупный JSONB-блоб §22-отчёта — блокирует event loop на каждый запрос чата (LLM-ветка корректно мостится через run_in_threadpool, а это чтение — нет). Docstring ссылается «как get_parcel_forecast», но тот — sync `def` и исполняется в threadpool; locations.py/insights.py прямо предупреждают, что «async def + sync db.execute заблокировало бы loop». Под параллельной нагрузкой чата деградирует латентность всех эндпоинтов. ## Suggested fix Сделать хендлер sync `def ask(...)` (FastAPI уведёт в threadpool), либо обернуть get_report_for_chat в run_in_threadpool, как уже сделано для orchestrate_chat. ## Verify notes (вердикты адверсариальных верификаторов) - [real/P3] Трассировка: async def ask (chat.py:53) на строке 66 синхронно зовёт get_report_for_chat → latest_run_for → db.execute(...).first() — блокирующий psycopg3 I/O, тянущий «тяжёлый result-блоб (~90 ключей JSONB)» (repository.py:234) в event loop'е. LLM-ветка мостится через run_in_threadpool (стр. 132), это чтение — нет; в det-ветке await'ов нет вовсе. locations.py:18/insights.py:19 документируют паттерн как блокирующий loop; get_parcel_forecast — sync def. P3: деградация латентности. - [refuted/P3] Механика верна, но это документированный house-style: backend.md требует «FastAPI handlers: async def»; ≥6 async-хендлеров (by-bbox — самый горячий, poi-score, competitors, best-layouts, PDF-рендер WeasyPrint) делают sync-БД/CPU в loop напрямую. Спорное чтение — индексированный SELECT LIMIT 1 (idx_analysis_runs_cad_created), миллисекунды; тяжёлая LLM-ветка мостится корректно. Деградация нереалистична при auth-gated low-traffic чате. Консистентность-рефакторинг, не дефект. ## Provenance - Finders: `api-core` - Confidence: 0.6 - Verifier votes: 1 real / 1 refuted (на основании 2 попыток) - Originally batched at: main@d796027
bot-backend added the
Fable 5 ревью
label 2026-06-13 04:58:12 +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#1245
No description provided.