- Зачем:
- Codex-диагноз нашёл корень нестабильности runtime-гейта: гонка
остановки live-генератора, batch публикуется по топикам без
атомарности, seam-SQL маскирует непарные строки под смену фактуры;
- попутно закрыт второй открытый вопрос задачи 13 - запасная ветка
рождения визита уже хранит донора (фикс задачи 09).
- Что:
- задача 20: диагноз с судьбой трёх гипотез, направление фикса
(управляемая остановка live + precheck непарных строк), статус
ready-for-agent;
- задача 13: вопрос про fallback-ветку закрыт, статус ready-for-human
(осталось решение по развилке реализации).
- Проверка:
- утверждение про донора перепроверено по generation.py:194-209;
эмпирика диагноза - в логах прогонов, пути в задаче 20.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6.1 KiB
Status: ready-for-agent
Runtime-проверка стыка нестабильна: фактура меняется через раз
Parent
.scratch/generator-model-time-startup-history/PRD.md
Что нашли
Два подряд прогона make generated-history-runtime-check на одном и том же
стенде (2026-07-07, проверка пути менти) дали разный результат:
- Прогон 1 (20:18–20:20): красный —
Ошибка: per-event фактура меняется на стыке: 8/19(у 8 из 19 визитов, переживших границу backfill->live, поменялась per-event фактура). При этомduplicate_events=0, events=2776. - Прогон 2 (21:5x, та же команда, без изменений кода): зелёный — «runtime-проверка startup-history/live seam прошла», конфликтов 0, events=2815.
Конфигурация проверки: GEN_LAUNCH_PROFILE=daily-wave,
GEN_HISTORY_DURATION=1h, GEN_MODEL_T_END=2026-01-01T01:00:00+00:00
(зашита в scripts/run_generated_history_runtime_check.sh).
Почему это важно
- Это гейт, которому мы доверяем стык backfill->live (задача 17); флаки-гейт ничего не гарантирует: красный пугает зря, зелёный ничего не доказывает.
- Смена фактуры на стыке — класс дефекта задачи 09, который считается закрытым (донор фактуры сохранён в state, тихие fallback'и заменены на ошибки). Либо фикс неполон, либо есть второй источник расхождения.
- Задача 13 (глагол next-day) навешивает на этот же механизм цепочку границ — ей нужен доверенный, стабильный гейт.
Диагноз (Codex, 2026-07-07; ключевой факт перепроверен координатором)
Корень: гонка остановки live-генератора, а не смена фактуры. Цепочка:
run_generated_history_runtime_check.sh останавливает live сразу после первых
новых STG-строк -> генератор публикует batch по четырём топикам
последовательно, без атомарности -> docker compose stop generator может
оборвать процесс между топиками -> часть browser-событий остаётся без парных
location/device/geo -> DDS строит dds.event через LEFT JOIN location,
и такие строки получают NULL в referer/utm -> seam-SQL считает это «сменой
фактуры внутри click_id».
Эмпирика: в красном прогоне browser_raw=2776, но location_raw=2736 —
40 live-событий без пары; в зелёном browser_raw=location_raw=2815, поэтому
проверка прошла (хотя device/geo и там отстали: 2781).
Судьба гипотез:
- Запасная ветка рождения — опровергнута: ветка уже хранит донора
(
generation.py:194-209, комментарий «Запасная ветка тоже восстановима») и громко падает на неполных locations. Перепроверено координатором по коду. - Недетерминизм live — подтверждена частично: решает не сид, а настенный момент остановки процесса и какие топики успели дописаться.
- Проверочный SQL — опровергнута в формулировке: поля не «легитимно различаются», SQL маскирует пропущенный location под «смену фактуры».
Направление фикса (из диагноза)
- Основное: сделать остановку live управляемой — завершать после полного
batch/tick и flush всех топиков (bounded live mode или ожидание записи
generator_batch_historyс полными sent-счётчиками). - Дополнительно: precheck в seam-check на непарные browser/location/device/geo live-строки — чтобы ошибка называла реальную причину, а не «фактура поменялась».
- Просто увеличить sleep перед stop — отклонено: снижает вероятность, но гонку не убирает.
Acceptance criteria
- Причина расхождения 8/19 найдена и названа (код, не догадка) — см. «Диагноз» выше.
- Остановка live в runtime-check управляемая: batch дописывается во все топики целиком до остановки (направление фикса, пункт 1).
- Seam-check различает «непарные live-строки» и «смена фактуры»: precheck называет реальную причину (пункт 2).
make generated-history-runtime-checkстабилен: N подряд прогонов зелёные (N >= 3), зафиксировано в задаче.
Blocked by
- Нет. Диагноз можно начинать сразу; стенд воспроизводит через раз.
Связано: 09-seam-browser-fixture-not-preserved.md (класс дефекта и решение
про донора), 13-backfill-top-up-from-snapshot.md (нуждается в доверенном
гейте на цепочке границ), 17-trusted-checks-startup-history-superset.md
(появление этого гейта).