[Fable 5][P3] noise_loader: loop-UPSERT без begin_nested — один дефектный OSM-way (3-точечное кольцо) валит весь weekly-синк на каждом прогоне #1231

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

Из армейского ревью Claude Fable 5 (2026-06-11)

Confirmed by 2/2 адверсариальных верификатора, severity P3 (data-integrity), confidence 0.6.

Файл

backend/app/services/site_finder/noise_loader.py:206

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

            result = db.execute(
                text(f"""
                    INSERT INTO osm_noise_sources_ekb
                        (osm_type, osm_id, source_type, road_class, name, geom, tags, fetched_at)
                    VALUES (
                        :osm_type, :osm_id, :source_type, :road_class, :name,
                        {geom_sql},
                        CAST(:tags AS jsonb), NOW()

Why bug

Per-row INSERT в цикле без with db.begin_nested() — нарушение закона SAVEPOINT (канон рядом: pzz_loader.py:112). Реальный триггер: _way_to_polygon_wkt (стр. 130-136) для замкнутого natural=water way из 3 точек (points[0]==points[-1]) даёт POLYGON((A,B,A)); PostGIS отвергает кольцо <4 точек → исключение → откат всей транзакции и raise: все строки прогона теряются, тот же way отравляет каждый следующий прогон → шум/гидро/utility-слои не обновляются. Тот же паттерн в poi_loader.py:156.

Suggested fix

Обернуть каждую итерацию в with db.begin_nested(): + try/except с logger.warning и счётчиком skipped (как в pzz_loader); в _way_to_polygon_wkt требовать ≥4 точки итогового кольца, иначе fallback на LineString/skip.

Verify notes

  • [real/P3] Loop-UPSERT (стр. 206) без begin_nested; канон рядом (pzz_loader.py:112) его использует. Трасса: natural=water way [n1,n2,n1] → _way_to_polygon_wkt: len==3 проходит guard, кольцо уже замкнуто → POLYGON((A,B,A)) → ST_GeomFromText: «geometry requires more points» → исключение вне SAVEPOINT → db.rollback()+raise теряет все строки прогона; тот же way возвращается еженедельно → weekly noise/water/utility синк падает каждый раз. Failure громкий, старые данные в таблице остаются → P3.
  • [real/P3] Цикл per-row UPSERT (стр.157/206) без begin_nested/try; канон в том же пакете — pzz_loader.py:111 («ошибка одной записи не откатывала всю транзакцию»), 15+ тасков следуют закону. Триггер реален: _way_to_polygon_wkt пропускает замкнутое 3-точечное кольцо [A,B,A] (guard len<3 не ловит) → PostGIS отвергает ринг <4 точек → outer rollback+raise (233-235), весь прогон потерян, повтор еженедельно. Смягчение: rollback полный (нет corruption), фейл громкий, триггер редкий → P3.

Provenance

  • Finders: site-finder-B
  • Confidence: 0.6
  • Originally batched at: main@d796027
## Из армейского ревью Claude Fable 5 (2026-06-11) Confirmed by 2/2 адверсариальных верификатора, severity **P3** (data-integrity), confidence 0.6. ## Файл [`backend/app/services/site_finder/noise_loader.py:206`](backend/app/services/site_finder/noise_loader.py:206) ## Evidence (цитата кода) ``` result = db.execute( text(f""" INSERT INTO osm_noise_sources_ekb (osm_type, osm_id, source_type, road_class, name, geom, tags, fetched_at) VALUES ( :osm_type, :osm_id, :source_type, :road_class, :name, {geom_sql}, CAST(:tags AS jsonb), NOW() ``` ## Why bug Per-row INSERT в цикле без `with db.begin_nested()` — нарушение закона SAVEPOINT (канон рядом: pzz_loader.py:112). Реальный триггер: _way_to_polygon_wkt (стр. 130-136) для замкнутого natural=water way из 3 точек (points[0]==points[-1]) даёт POLYGON((A,B,A)); PostGIS отвергает кольцо <4 точек → исключение → откат всей транзакции и raise: все строки прогона теряются, тот же way отравляет каждый следующий прогон → шум/гидро/utility-слои не обновляются. Тот же паттерн в poi_loader.py:156. ## Suggested fix Обернуть каждую итерацию в `with db.begin_nested():` + try/except с logger.warning и счётчиком skipped (как в pzz_loader); в _way_to_polygon_wkt требовать ≥4 точки итогового кольца, иначе fallback на LineString/skip. ## Verify notes - [real/P3] Loop-UPSERT (стр. 206) без begin_nested; канон рядом (pzz_loader.py:112) его использует. Трасса: natural=water way [n1,n2,n1] → _way_to_polygon_wkt: len==3 проходит guard, кольцо уже замкнуто → POLYGON((A,B,A)) → ST_GeomFromText: «geometry requires more points» → исключение вне SAVEPOINT → db.rollback()+raise теряет все строки прогона; тот же way возвращается еженедельно → weekly noise/water/utility синк падает каждый раз. Failure громкий, старые данные в таблице остаются → P3. - [real/P3] Цикл per-row UPSERT (стр.157/206) без begin_nested/try; канон в том же пакете — pzz_loader.py:111 («ошибка одной записи не откатывала всю транзакцию»), 15+ тасков следуют закону. Триггер реален: _way_to_polygon_wkt пропускает замкнутое 3-точечное кольцо [A,B,A] (guard len<3 не ловит) → PostGIS отвергает ринг <4 точек → outer rollback+raise (233-235), весь прогон потерян, повтор еженедельно. Смягчение: rollback полный (нет corruption), фейл громкий, триггер редкий → P3. ## Provenance - Finders: `site-finder-B` - Confidence: 0.6 - Originally batched at: main@d796027
bot-backend added the
Fable 5 ревью
label 2026-06-13 04:49:47 +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#1231
No description provided.