diff --git a/History/gemini-event-sourcing-analysis.md b/History/gemini-event-sourcing-analysis.md new file mode 100644 index 0000000..0cb72ff --- /dev/null +++ b/History/gemini-event-sourcing-analysis.md @@ -0,0 +1,43 @@ +# Анализ уязвимостей Event Sourcing — Gemini Web + +**Дата:** 2026-06-21 + +## 🚨 Критические уязвимости + +### 1. Race Condition в `seq` +`apply_events.cfm` — `MAX(seq)` + `seq++` в цикле. При параллельных запросах — одинаковые seq. +**Фикс:** `INSERT ... SELECT COALESCE(MAX(seq),0)+1` атомарно. + +### 2. Опустошение контракта при full_replace +`apply_events.cfm` — DELETE из spec_current ДО проверки что ops не пуст. LLM упала → спецификация стёрта. +**Фикс:** валидация ops.length перед удалением. + +### 3. Падение типизации price/qty +`apply_events.cfm` — LLM может вернуть строку вместо числа. `cf_sql_float` падает. +**Фикс:** `isNumeric()` перед float. + +### 4. N+1 запросов в UPDATE +`apply_events.cfm` — для каждого UPDATE отдельный SELECT. 200 позиций = 200 запросов. +**Фикс:** один SELECT всех строк до цикла. + +### 5. Построчный INSERT full_replace +`apply_events.cfm` — цикл INSERT вместо массового. +**Фикс:** `INSERT INTO ... SELECT`. + +### 6. Хэш зависит от LLM-форматирования +`apply_events.cfm` — `md5(lower(trim(name)) || date_start)`. LLM написала «Услуги» vs «Услуга» → разный хэш → ADD/DELETE вместо UPDATE. +**Фикс:** LLM сама возвращает target_hash. + +### 7. Несовместимость типов last_event_id +`apply_events.cfm` — UUID пишется как `cf_sql_varchar`. +**Фикс:** правильный UUID-тип. + +## Файлы для анализа + +| Файл | Роль | +|------|------| +| `contractor/apply_events.cfm` | Транзакционное применение ops | +| `contractor/db.cfc` | Схема таблиц spec_events, spec_current | +| `contractor/deploy/llm_prompt.py` | Промпты LLM (ВМ) | +| `contractor/deploy/convert_server.py` | SSE + вызов LLM + apply_events (ВМ) | +| `contractor/index.cfm` | UI, EventSource, раздел сравнения |