Status: done # Портативный артефакт стартовой истории и runbook по стенду ## Parent `.scratch/generator-model-time-startup-history/PRD.md` ## Why Сейчас стартовая история персистится только в Kafka compact-топиках (`generator_state`, `generator_startup_history_manifest`) и в ClickHouse. Чистая пересборка стенда (`make generated-history-analytics` делает `down -v`) каждый раз **заново генерирует** backfill. Портативного файла-артефакта, который можно сгенерировать один раз и быстро восстановить на чистом стенде без запуска генератора, нет. Из-за этого неудобно: мгновенно сбросить стенд, держать длинную стартовую историю (2+ суток, чтобы суточная волна повторялась на графике) без повторной генерации. Сейчас «дёшево» только live-возобновление из слепка и перезапуск без `down -v`; полный сброс требует регенерации. Этот пункт работает на главную цель: если стенд поднимается одной командой и есть короткий runbook, генератор остаётся скрытой инфраструктурой и менти не нужно знать его устройство. Развилка курса «урок про генератор vs скрытая инфраструктура» уже закрыта в пользу скрытой инфраструктуры (`docs/course/PRD.md` §7, 2026-07-04) — эта задача обеспечивает решению опору. ## What to build - **Экспорт** стартовой истории в портативный файл-артефакт: события (в формате сообщений топиков) плюс слепок состояния плюс манифест — один связный набор, чтобы не смешать `GEN_SEED`, `T0`, `T_end` и настройки генерации. - **Импорт** (решение 2026-07-04): воспроизвести события артефакта в Kafka-топики и вернуть слепок с манифестом в служебные compact-топики. **Напрямую в ClickHouse импорт не пишет ничего**: стенд наполняется штатным путём (Kafka engine + MV -> STG, батч-ETL -> витрины). Так не появляется обходного пути данных, каждый импорт заодно прогоняет весь пайплайн, а менти видит, как пустой стенд наполняется изучаемыми механизмами. Live продолжает с `T_end`. - **Громкий отказ при несовместимом state** (решение 2026-07-04, пересмотр правила спеки). Различать два случая. Нет состояния или оно повреждено -> чистый старт с предупреждением (как сейчас, оставить). Состояние есть и читается, но настройки несовместимы при `GEN_STATE_RESET=false` (оператор намерен продолжить) -> жёсткое падение с указанием разошедшихся полей (`seed`/`T0`/`timezone`/`speed`) и подсказкой выставить `GEN_STATE_RESET=true`, если новый мир нужен осознанно. Текущее тихое поведение — `service.py:217-220`. Правка идёт вместе с обновлением `docs/specs/2026-06-14-generator-model-time-and-startup-history.md`. - **Runbook «как пользоваться стендом на генерации»**: как сгенерировать, сохранить, восстановить, выбрать длительность стартовой истории; что дёшево (live-возобновление, перезапуск без чистки), а что требует регенерации. - Новые команды экспорта/импорта делать в стиле глаголов (явное действие одной командой), а не новыми комбинациями env-переменных. ## Acceptance criteria - [x] Есть команда экспорта: стартовая история -> портативный файл-артефакт (события + слепок + манифест) одним связным набором. - [x] Есть команда импорта: на чистом стенде артефакт воспроизводится в Kafka (события + служебные compact-топики) **без запуска генерации**; напрямую в ClickHouse импорт не пишет. После штатного ETL контрольные числа в ClickHouse совпадают с манифестом и исходной генерацией. - [x] После импорта live продолжает с `T_end`: без дублей на границе и без смешения миров. - [x] Сохранено антисмешивание: импорт отвергает артефакт, несовместимый по манифесту (`GEN_SEED`, `T0`, `T_end`, настройки генерации, версия state). - [x] Громкий отказ: живое читаемое состояние + несовместимые настройки при намерении продолжить -> падение с перечислением разошедшихся полей и подсказкой; нет состояния или повреждено -> чистый старт с предупреждением (как сейчас). Спека обновлена в этом же изменении. - [x] Runbook описывает генерацию один раз, дешёвое восстановление, выбор длительности и то, что переживает перезапуск, а что требует регенерации. - [x] Runbook — про **использование**, устройство генератора в нём не объясняется; за конструкцией он отсылает к `generator/README.md` и `docs/specs/`. - [x] Документы запуска (`README.md`, `docs/OPERATIONS.md`, `generator/README.md`) ссылаются на runbook. ## Notes - Опирается на спеку `docs/specs/2026-06-14-generator-model-time-and-startup-history.md`, разделы «Манифест стартовой истории» и «Повторяемая проверка в ClickHouse». - Спека уже упоминала будущий runbook «проверка генератора на стенде» — этот issue его и закрывает, расширяя до полного цикла «генерация — сохранение — восстановление». - Откуда экспорту брать события — решить при реализации и зафиксировать в спеке/runbook. Кандидаты: писать файл артефакта прямо при backfill (вторая копия рядом с публикацией в Kafka), вычитать топики событий (учесть retention) или выгрузить из STG (следить за точностью формата сообщений). Критерий выбора: артефакт должен байт в байт воспроизводить сообщения топиков. - Рекомендуемый режим ревью по coordinator-loop: **гейт** (state, сериализация, формат данных, правка спеки — всё из порогов риска). - Связано с `08-migrate-course-from-archive-seed.md`: миграция уроков идёт после этой задачи и будет ссылаться на runbook отсюда (номера отражают порядок, переставлены 2026-07-04). ## Идеи интерфейса — решения (2026-07-04) Бывший раздел «на будущее, не решено» разобран с пользователем. Судьба идей: - **Громкий отказ при несовместимом state** — включён в эту задачу (см. What to build и критерии). - **Глаголы / длительность / профили** — отдельная задача `11-generator-launch-verbs-and-profiles.md`, делать **после этой и до DAG-пульта**: чистый интерфейс «под капотом» делает DAG тонкой обёрткой с простыми и понятными параметрами. - **Airflow-DAG как пульт генератора** — приоритет поднят (пользователь, 2026-07-04): это будущий основной человеческий интерфейс стенда — «слишком сложно» лечится формой в веб-UI, а не только runbook'ом. Отдельная задача `12-generator-control-dag.md`, делать после задачи 11. - **Доливка прошлого кусочком** — отдельная задача `13-backfill-top-up-from-snapshot.md`, без приоритета. ## Blocked by - `.scratch/generator-model-time-startup-history/issues/05-startup-history-backfill-to-clickhouse.md` - `.scratch/generator-model-time-startup-history/issues/06-generated-history-as-analytics-source.md`