Files
clickstream-ch-kafka-supers…/docs/adr/0004-steady-stream-synthetic-generator.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

87 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0004: Steady-stream источник — синтетический иерархический генератор, не реплей
Принято: 2026-06-09
Статус: accepted
Связано: [`generator/KNOWN_ISSUES.md`](../../generator/KNOWN_ISSUES.md) (диагноз
дефекта), [`CONTEXT.md`](../../CONTEXT.md),
[ADR-0002](./0002-specs-as-durable-design-docs.md) (спеки как durable design-доки),
спека [`docs/specs/2026-06-09-generator-rework-hierarchical.md`](../specs/2026-06-09-generator-rework-hierarchical.md)
(форма доработки).
> Обновление (2026-06-14): тезис «генератор сосуществует с сидом, не заменяет
> его» частично пересмотрен в [ADR-0006](./0006-generation-as-sole-analytics-source.md)
> — для аналитического контура стенда генерация заменяет статический сид; сид
> выводится из оборота (целевым образом — полностью). Сосуществование остаётся
> верным лишь для переходной роли сида (палитра атрибутов / dev-фикстура).
## Решение
Режим `steady-stream` (живой поток на стенде) питается **синтетическим
генератором, переписанным с нуля по иерархической модели** «популяция
пользователей → сессии → события», а **не реплеем статического сида**. Модель
интенсивности текущего генератора (Poisson по тикам + дневной коэффициент +
jitter) сохраняется. Режим `bootstrap` (статический сид `data/*.jsonl`) и уроки
0–6 остаются прежними — генератор **сосуществует** с сидом, не заменяет его.
## Контекст
Проект сменил назначение на учебный стенд с курсом. Базовый курс стоит на
статическом сиде, и это осознанно: сид **честен внутри визита** (`click_id`
группирует несколько событий — настоящая воронка; по полному замеру 2026-06-10 —
1..27 событий, медиана 10, см. профиль сид-датасета в `CONTEXT.md`). Но у сида
два потолка, которые
сид принципиально не закрывает:
- **`users == sessions`** — каждый пользователь имеет ровно один `click_id` (1:1),
возвращающихся пользователей нет (см. `CONTEXT.md`).
- **одноразовость** — сид заливается батчем; не видно, как ClickHouse и витрины
ведут себя на непрерывном живом потоке.
Нужен режим, в котором стенд **живёт и движется** на правдоподобных данных
(воронка + жизнеподобные колебания интенсивности), при **скромном объёме** (у
менти может не быть мощного железа — на объём/стресс не закладываемся).
Двойная учебная ценность — ключевой критерий выбора: ценны не только *данные*
(живой стенд + честная пирамида `users < sessions < events`), но и **сам
генератор как объект изучения** — его генеративная модель достойна того, чтобы её
разбирать в курсе.
Текущая реализация генератора не дорабатывается инкрементально: у неё
концептуальный дефект модели сущностей (свежий `click_id` на каждое событие
схлопывает иерархию — см. `generator/KNOWN_ISSUES.md`), переписываем с нуля.
## Рассмотренные варианты
- **A — синтетический иерархический генератор (принято).** Популяция юзеров с
постоянным `user_domain_id` → 1..N сессий (`click_id` на сессию) → 1..M
упорядоченных по времени событий с правдоподобной воронкой. Единственный
вариант, дающий возвращающихся пользователей (`users < sessions < events`) и
учебную ценность самого моделирования. Цена — самый большой объём работы и
риск ошибиться в статистической модели.
- **C — реплей честного сида на часах.** Лить реальные записи сида в Kafka во
времени, переписывая `event_timestamp` в «сейчас», зацикливая пул и модулируя
rate. **Отклонено.** Дёшев и даёт гарантированно честную воронку почти без
риска, **но**: (1) обходит ровно ту генеративно-модельную часть, ради учебной
ценности которой всё и затевается; (2) наследует вырождение `users == sessions`
из сида — полную пирамиду не даёт никогда; (3) «бесконечность» = зацикленный
конечный пул.
- **B — минимальный «живой» генератор с грубой воронкой.** Тот же rewrite, но
воронка на фиксированных вероятностях, без глубины. Отклонено как
половинчатое: числа воронки менее убедительны, а вопрос возвратов всё равно
надо решать — то есть основной сложности не избегает.
## Последствия
- Режим `steady-stream` фиксируется как синтетическая генерация; направление
переоткрывать не нужно (типовой вопрос «почему не реплей?» закрыт здесь).
- `bootstrap`-сид и уроки 0–6 не трогаем; живой поток подаётся отдельным уроком 7.
- Контракт данных потока: здоровая пирамида `users < sessions < events`,
монотонное время внутри сессии, `click_id` переиспользуется внутри сессии.
Этот контракт наследуют будущие артефакты (спека доработки, урок 7, возможные
правки витрин).
- Детальная архитектура/требования — в спеке `2026-06-09-generator-rework-hierarchical.md`.
- **Статистическая модель** (распределения событий/сессия, сессий/пользователь,
межсессионные паузы; нужен ли настоящий session-timeout; персистентность
популяции через рестарты) **выносится в отдельную follow-up-спеку** и здесь
намеренно не фиксируется.