- Зачем:
- закрыть Open questions спеки формы доработки перед передачей на
реализацию; адверсариальное ревью показало, что прежние ориентиры
(популяция/паузы/интенсивность) взаимно несовместимы, а документы
опираются на неверный факт о сиде («1..7 событий на визит»).
- Что:
- добавлена docs/specs/2026-06-10-generator-math-model.md: марковская
цепочка по страницам, формула связи «популяция-интенсивность-пауза»
(λ по умолчанию 30/мин), кулдаун возврата, правило 30 минут на рестарт,
критерии приёмки.
- в CONTEXT.md добавлен профиль сид-датасета (полный замер: длины визитов
1..27, медиана 10, конверсия 25%, петли и события после /confirmation)
и исправлено ложное «разброс времени внутри click_id <= 1 мин».
- исправлен факт «1..7 событий» в KNOWN_ISSUES.md и ADR-0004; критерии
Validation спеки формы доработки приведены к фактам сида.
- Проверка:
- перекрёстные ссылки между спеками/ADR/CONTEXT.md открываются; цифры
профиля сида воспроизводятся скриптом подсчёта по полным data/*.jsonl.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 lines
7.0 KiB
Markdown
81 lines
7.0 KiB
Markdown
# 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)
|
||
(форма доработки).
|
||
|
||
## Решение
|
||
|
||
Режим `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-спеку** и здесь
|
||
намеренно не фиксируется.
|