- Зачем:
- ADR-0006 сделал генерацию единственным источником аналитики, а статический
сид — архивным; глоссарий и спеки это ещё не отражали.
- Что:
- CONTEXT.md: «статический сид» переименован в «архивный статический сид»
(короткое имя сохранено), описан как временная кладовка значений с целью
полного вывода; «стартовая история» получила синонимы «стартовый сид» и
«новый сид»; раздел «Слои данных» отмечает переход аналитики на генерацию.
- мат-спека: разделы «Персистентность через рестарты» и «Воспроизводимость»
помечены как переописанные в спеке модельного времени (ссылкой, без повтора).
- спека модельного времени: синоним «стартовый сид» добавлен в определение и
в заметку о влиянии на документацию.
- Проверка:
- git diff: термины и перекрёстные ссылки читаются непротиворечиво; ADR не
правились (статус «архивный» не переносится в документы до ADR-0006).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
17 KiB
Модельное время на практике: сохранение состояния, заливка прошлого и стартовая история
Дата: 2026-06-14
Статус: Draft
Связано: ADR-0005 (решение про модельные
часы — эта спека его дорабатывает), ADR-0006
(стартовая история как источник аналитики), мат-спека
2026-06-10-generator-math-model.md
(её разделы «Персистентность через рестарты» и «Воспроизводимость» здесь
приводятся в соответствие с модельным временем — не повторяются, а
переописываются ссылкой), CONTEXT.md, задача
06-state-v2-and-restart
(сохранение состояния построено на настенных часах).
Уровень документа — модель и правила, как в мат-спеке. Код, имена настроек, формат конфигурации и сам способ управления ходом часов — за исполнителем, в рамках правил этой спеки (как условились в ADR-0005).
Проблема
ADR-0005 решил отвязать время генератора от реальных часов и ввёл три скорости его хода: обычную (×1), ускоренную (×K) и мгновенную «промотку» прошлого. Но два правила старой модели — как генератор сохраняет состояние между перезапусками и как добивается повторяемости — описаны от реальных часов. А ADR-0006 сделал стартовую историю (готовое сгенерированное прошлое) единственным источником данных стенда.
Осталось довести модель до конца: как работает промотка прошлого, его заморозка и непрерывный запуск стенда с этого момента; как при этом меняются правила сохранения состояния и повторяемости; и как всё это проверить. Всё это — один механизм: промотать прошлое → заморозить → продолжить живьём. Это один и тот же путь сохранения и восстановления, просто с разных сторон.
Цели
-
Дать генератору собственные часы и сделать поток повторяемым. Генератор должен отсчитывать время от своей точки отсчёта (ниже — «стартовая модельная точка
T0»), а не от реальных часов компьютера. Тогда при одних и тех же настройках он каждый раз порождает один и тот же поток — это нужно для тестов и для повторяемых уроков. -
Переписать правила сохранения и восстановления состояния по этим часам. Сейчас они завязаны на реальное время. Главное правило — «если посетитель молчал дольше 30 минут, считаем, что он ушёл» — должно мерить эти 30 минут по часам генератора. И поток больше не должен зависеть от того, в котором часу реального дня запущен генератор.
-
Научиться быстро «проматывать» прошлое и замораживать его как стартовый набор данных. Генератор прокручивает время без пауз от точки отсчёта до нужного момента, порождает события прошлого и сохраняет «слепок» своего состояния. Этот замороженный набор — то, с чего свежий стенд начинает жить, уже имея историю: здоровую пирамиду «пользователей меньше, чем визитов, а визитов меньше, чем событий» с первой минуты.
-
Описать, как всё это проверить — в два шага. Сначала числами: агент поднимает стенд и сверяет данные в ClickHouse. Потом глазами: человек смотрит на дашборды и видит, что распределение похоже на задуманное, а стенд «дышит» во времени.
Чего здесь не делаем
- Не учим генератор придумывать «фактуру» сам (браузеры, гео, устройства, метки кампаний). Это отдельная спека — следствие ADR-0006. Пока её нет, стартовая история берёт фактуру из статического сида; это осознанно временно.
- Не описываем здесь перестройку процесса на новый сид (загрузка
kafka_load_dag, витрины/Superset, уроки) — это решено в ADR-0006 и проектируется отдельно. Эта спека — только про сам генератор. - Не фиксируем имена настроек, формат конфигурации и сам алгоритм — это за исполнителем.
- Не добавляем новые типы событий и инкрементальную загрузку ETL.
Модель
Точка отсчёта и скорость хода часов
У генератора своя точка отсчёта времени — стартовая модельная точка T0
(задаётся в настройках). В метку события (event_timestamp) пишется это
внутреннее время. Скорость, с которой оно идёт относительно реальных часов,
переключается (в ADR-0005 — «драйвер часов»):
- ×1 — как реальное время;
- ×K — в
Kраз быстрее; - заливка прошлого — время гонится без пауз от
T0до нужного момента (особый случай очень большогоK).
Повторяемость
При одном и том же зерне GEN_SEED, одной и той же T0 и одной скорости
генератор каждый раз даёт один и тот же поток. Это убирает прежнюю оговорку
мат-спеки «запуск в другой час даёт другой поток»: дневной коэффициент
(день/ночь) теперь считается по внутреннему времени от T0, а не по реальным
часам. Так раздел «Воспроизводимость» мат-спеки приводится в соответствие с
модельным временем.
Заливка прошлого и стартовая история
«Промотать» прошлое — значит прогнать время без пауз от T0 до момента T_end и
сгенерировать события этого отрезка. На выходе — события за [T0, T_end] и
слепок состояния генератора на момент T_end.
События плюс слепок и есть стартовая история («стартовый сид» или «новый сид» —
синонимы, новое значение слова «сид» не заводим). При создании стенда это прошлое заливается, и
генератор готов продолжить ровно с T_end. Стенд сразу живёт с готовой историей —
с настоящей пирамидой «пользователей меньше, чем визитов, визитов меньше, чем
событий», без вырождения статического сида, где пользователей ровно столько же,
сколько визитов.
Сохранение и восстановление состояния
Правило «молчал дольше 30 минут — посетитель ушёл» остаётся; меняется только от какого момента отсчитывать эти 30 минут:
- после сбоя — от реального «сейчас» (время и правда прошло) → как сегодня;
- при запуске со стартовой истории — от метки слепка (
T_end) → разрыва почти нет, активные визиты не обрываются, мир продолжается без шва.
Паузы между визитами одного пользователя и обязательная пауза перед возвратом
тоже считаются по внутренним меткам времени, а не по числу тактов. Если
сохранённое состояние повреждено или его нет — генератор стартует с чистого листа
(свежая популяция от GEN_SEED) и пишет предупреждение в лог. Так раздел
«Персистентность» мат-спеки приводится в соответствие с модельным временем.
С какой скоростью стенд живёт дальше
После старта стенд продолжает жить на выбранной скорости. Скорость — это ручка под задачу: чтобы увидеть медленные вещи (возвраты, сдвиг воронки после правки таблицы переходов, «дыхание» суточной нагрузки) за учебное время, нужно ускорение (×K) — иначе суточная волна разворачивается реальные сутки. Какой скорость будет по умолчанию (×1 «как настоящий сайт» или ускоренная «учебная») — решает урок/исполнитель; спека лишь фиксирует, что это ручка и что именно на ней держится наблюдаемость медленных явлений.
Временная опора на сид (фактура)
Пока генератор не умеет придумывать фактуру сам (ADR-0006), стартовая история одевает события в данные из статического сида (браузер, гео, устройство, метки кампаний). Это временно и не мешает: механизм времени и стартовой истории не ждёт синтеза фактуры, а сид до его появления остаётся кладовкой готовых значений — но уже не источником аналитики.
Проверка
Два шага — это разделение труда: первый объективный и повторяемый (его делает агент или CI), второй — человеческий взгляд.
Шаг 1 — агент сверяет числа в ClickHouse
На чистом стенде с фиксированными GEN_SEED и T0 залить стартовую историю,
прогнать STG→DM и проверить:
- пирамида: уникальных пользователей меньше, чем визитов, а визитов меньше, чем событий;
- воронка убывает по шагам
/home → товары → /cart → /payment → /confirmation; доля дошедших до/confirmation— в нужном коридоре; - возвраты: у части пользователей больше одного визита;
- длина визита и доля коротких визитов — в коридорах мат-спеки.
Главное: проверки повторяемы (тот же GEN_SEED и T0 → те же числа в
пределах допуска) и записаны как команды и запросы, чтобы их мог прогнать агент
или CI без человека. Сами запросы и числовые коридоры — при реализации.
Шаг 2 — человек смотрит на дашборды
Глазами убедиться, что:
- распределение похоже на задуманное — на наши спроектированные распределения (мат-спека), а не на профиль чужого сида;
- стенд «дышит» — видна суточная волна нагрузки, копятся возвраты и воронка (заметно на ×K).
Здесь всплывает нехватка: дашборда с распределением сгенерированных данных пока нет. Superset построен на сиде, а Grafana показывает только скорость работы сервиса, не форму данных. Закрыть можно двумя способами: переключить Superset на генерацию (часть большой миграции — позже) или добавить простую панель «распределение из ClickHouse» в Grafana. Пошаговые действия шага 2 — в будущий runbook «проверка генератора на стенде».
Решения и отклонённые варианты
- Приняли: одна спека на время, сохранение состояния и стартовую историю — это один механизм, а не три задачи.
- Приняли: своя точка отсчёта
T0как опора повторяемости; дневной коэффициент считается по внутреннему времени. - Приняли: проверка в два шага (агент — числа, человек — глаза).
- Отклонили: жёстко подгонять генерацию под профиль сида (см. ADR-0006).
- Отклонили: приводить сохранение состояния в соответствие с модельным временем отдельно от стартовой истории — это разрезало бы один механизм надвое.
Влияние на документацию
- Мат-спека: разделы «Персистентность через рестарты» и «Воспроизводимость» пометить как переописанные в модельном времени этой спекой (ссылкой, без повтора).
- ADR-0005: направление «стартовая история» — отмечено как запущенное.
- CONTEXT.md: «стартовый сид» / «новый сид» = «стартовая история стенда» (синонимы, не новое значение); роль статического сида — по ADR-0006.
- Будущий runbook «проверка генератора на стенде» — шаги шага 2.
generator/README.md,docs/OPERATIONS.md— при реализации: скорость хода часов, ×K, стартовая история, проверки шага 1.