Files
clickstream-ch-kafka-supers…/docs/specs/2026-06-14-generator-model-time-and-startup-history.md
T
ddadminandClaude Opus 4.8 49512b190a docs(generator): зафиксированы источник аналитики и стартовая история
- Зачем:
  - генератор даёт здоровую пирамиду, и стенду нужен единый источник аналитики вместо вырожденного статического сида.
- Что:
  - добавлен ADR-0006: генерация — единственный источник аналитики, статический сид становится архивным (кладовка значений до синтеза фактуры).
  - добавлена спека модельного времени: точка отсчёта, заливка прошлого, стартовая история, сохранение состояния, воспроизводимость и проверка в два шага.
  - в ADR-0004 и ADR-0005 добавлены указатели вперёд на ADR-0006 и спеку.
- Проверка:
  - чтение документов; перекрёстные ссылки между ADR-0004/0005/0006 и спекой согласованы.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:47:20 +03:00

17 KiB
Raw Blame History

Модельное время на практике: сохранение состояния, заливка прошлого и стартовая история

Дата: 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.