- Зачем:
- после coordinator-loop нужно независимое ревью результатов модельного
времени и стартовой истории; пропущенный внешний review gate после задачи 5
закрыт другой родословной.
- Что:
- добавлен verification-handoff: что проверено независимо, дефект стыка
(issue 09) и открытые пробелы (×K, crash recovery, коридоры мат-спеки,
воспроизводимость, review gate задачи 3).
- заведены issues 08 (портативный артефакт + runbook + идеи интерфейса),
09 (баг браузерной фактуры на стыке), 10 (читаемость гео-карты).
- в docs/course/PRD.md §7 — открытый вопрос «генератор как скрытая
инфраструктура vs отдельный урок».
- Проверка:
- git show --stat HEAD
- чтение .scratch/handoffs/2026-06-14-generator-model-time-verification-review.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.3 KiB
Status: needs-triage
Портативный артефакт стартовой истории и 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. Портативного файла-артефакта, который можно
сгенерировать один раз и быстро залить на чистый ClickHouse без запуска
генератора, нет.
Из-за этого неудобно: раздать готовое демо, мгновенно сбросить стенд, держать
длинную стартовую историю (2+ суток, чтобы суточная волна повторялась на графике)
без повторной генерации. Сейчас «дёшево» только live-возобновление из слепка и
перезапуск без down -v; полный сброс требует регенерации.
Этот пункт работает на главную цель: если стенд поднимается одной командой и есть
короткий runbook, генератор становится скрытой инфраструктурой и менти не нужно
знать его устройство. Связано с открытым вопросом курса про отдельный урок по
генератору (см. docs/course/PRD.md, §7).
What to build
- Экспорт стартовой истории в портативный файл-артефакт: события плюс слепок
состояния плюс манифест — один связный набор, чтобы не смешать
GEN_SEED,T0,T_endи настройки генерации. - Импорт: залить артефакт на чистый ClickHouse и Kafka без прогона генерации;
live-режим продолжает с
T_end. - Runbook «как пользоваться стендом на генерации»: как сгенерировать, сохранить, восстановить, выбрать длительность стартовой истории; что дёшево (live-возобновление, перезапуск без чистки), а что требует регенерации.
Acceptance criteria
- Есть команда экспорта: backfill -> портативный файл-артефакт (события + слепок + манифест).
- Есть команда импорта: артефакт -> чистый ClickHouse без запуска генератора; контрольные числа манифеста и ClickHouse совпадают с исходной генерацией.
- Сохранено антисмешивание: импорт отвергает артефакт, несовместимый по
манифесту (
GEN_SEED,T0,T_end, настройки генерации, версия state). - Runbook описывает генерацию один раз, дешёвое восстановление, выбор длительности и то, что переживает перезапуск, а что требует регенерации.
- Документы запуска (
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 его и закрывает, расширяя до полного цикла «генерация — сохранение — восстановление».
- Связано с
07-migrate-course-from-archive-seed.md: удобный стенд упрощает выбор «адаптировать уроки», а не писать тяжёлый урок про генератор.
Идеи интерфейса (на будущее, не решено)
Запуск сейчас недружелюбный: поведение собирается из ~10 связанных env-переменных,
T_end задаётся абсолютной меткой вместо длительности, а несовпадение настроек при
live-продолжении даёт тихий «свежий старт» (warning в лог, общее сообщение, без
указания разошедшегося поля — service.py:217-220). Идеи, как сделать удобнее:
- Глаголы вместо матрицы флагов: явные
backfill/continue/reset, а не комбинацияGEN_RUN_MODE+GEN_STATE_RESET. - Длительность как длительность и профили:
HISTORY_DURATION=2dвместо ручного расчётаT_end; именованные профили вместо повторения блока из ~10 переменных. - Громкий и адресный отказ при несовпадении (пересмотр решения спеки). Сейчас
при
GEN_STATE_RESET=falseнесовместимый по настройкам state молча ведёт к чистому старту (service.py:217-220) — это сознательный выбор спеки ради устойчивости. Предложение: различать два случая. Нет состояния или оно повреждено -> чистый старт с предупреждением (как сейчас, оставить). Состояние есть и читается, но настройки несовместимы приGEN_STATE_RESET=false(оператор намерен продолжить) -> жёсткое падение с указанием разошедшихся полей (seed/T0/timezone/speed) и подсказкой выставитьGEN_STATE_RESET=true, если новый мир нужен осознанно. Меняет правило спеки «несовместимо -> чистый старт», поэтому правка идёт вместе с обновлениемdocs/specs/2026-06-14-generator-model-time-and-startup-history.md. - Доливка прошлого кусочком: backfill, продолжающий слепок от
T_end(сейчас backfill всегда стартует с чистого состояния отT0,service.py:178-185). - Airflow DAG как пульт запуска (идея пользователя, 2026-06-14): обернуть операции
генератора в параметризованный DAG (params: режим,
T0, длительность, скорость, seed) — UI, валидация настроек против манифеста до запуска, повторные попытки, наглядность. Хорошо ложится на ограниченный backfill/доливку (конечная задача); непрерывный live — это долгоживущий сервис compose, DAG его скорее стартует/останавливает, чем держит внутри таска. Бонус: такой DAG сам по себе учебный (тема урока 4 — оркестрация Airflow), что ближе к цели курса, чем устройство генератора.
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