# CONTEXT.md — глоссарий домена

Доменный язык стенда: как мы называем сущности кликстрима и что под ними
понимаем. Один термин — одно имя. Ведётся вместе с `docs/adr/` (см.
[ADR-0001](./docs/adr/0001-spec-adr-issue-layout.md)).

## Сущности

### Пользователь (user)

`user_domain_id` (`UUID`) — постоянный идентификатор пользователя (cookie-уровень),
переживает отдельные визиты. Источник — `device_events`, привязан к `click_id`.
В витринах: `uniqExact(user_domain_id)`.

### Визит / сессия (visit / session)

`click_id` (`UUID`) — **визит**: envelope из одного и более событий с общим
контекстом device/geo. В DDL `dds.click` описана как «контекст сессии
пользователя» (см. [`sql/ddl/dds/30_dds.sql`](./sql/ddl/dds/30_dds.sql)).

Важно: в источнике **нет отдельного session-таймаута** (как Snowplow
`domain_sessionid`). Поэтому в этой модели **сессия ≡ визит ≡ `click_id`** —
группа событий под одним идентификатором, а не окно активности по тайм-ауту.
Если в будущем понадобится «настоящая» сессия по 30-минутному окну неактивности —
это отдельная производная над `user_domain_id` + `event_ts`, и на сиде она дала
бы **другие** группы: в полном сиде 11 внутрисессионных пауз превышают 30 минут,
а разброс времени внутри `click_id` доходит до 49 минут (см. профиль
сид-датасета ниже; ранее здесь ошибочно значилось «разброс ≤ 1 мин» — это был
замер по малому срезу файла).

«Сессию» и «визит» используем как синонимы; в UI предпочитаем «визит», когда важно
подчеркнуть, что это не сессия-по-тайм-ауту.

### Событие (event)

`event_id` (`UUID`) — отдельное действие пользователя в рамках визита: `pageview`,
`click`, `purchase`, `add_to_cart` и т.п. (поле `event_type`). Источник —
`browser_events` + `location_events`. В витринах: `count()`.

## Иерархия

```
user_domain_id  (пользователь, постоянный)
  └── click_id  (визит/сессия — 1..N событий с общим device/geo)
        └── event_id  (событие: pageview / click / purchase ...)
```

Здоровые данные дают пирамиду `users ≤ sessions ≤ events`.

## Термины потоковой генерации (steady-stream)

Относятся к синтетическому потоку из генератора (режим `steady-stream`), не к
статическому сиду. Решение и контекст — [ADR-0004](./docs/adr/0004-steady-stream-synthetic-generator.md),
форма доработки — [спека генератора](./docs/specs/2026-06-09-generator-rework-hierarchical.md).

### Популяция пользователей (user population)

Множество пользователей с **постоянными** `user_domain_id`, которые генератор
держит во времени и из которых разыгрывает активность. В отличие от сида (где
пул `user_domain_id` плоский и 1:1 с визитами), популяция — это источник
возвратов: один и тот же пользователь порождает несколько визитов.

### Возвращающийся пользователь (returning user)

Пользователь, открывающий **более одного** визита (`click_id`) во времени, с
межсессионными паузами. Эталонный мир уже содержит возвраты: это замороженный
LIVE-мир с 4 056 пользователями и 26 083 визитами, поэтому уже при импорте
выполняется `users < sessions`. Режим `continue` продолжает этот мир: итоги
растут дальше и зависят от длительности запуска у каждого менти.

### Три значения слова «сид»

Слово перегружено — в разговоре про генератор это **три разные сущности**, их
нельзя путать (см. [ADR-0005](./docs/adr/0005-generator-model-clock.md)):

- **`GEN_SEED`** — зерно ГПСЧ генератора (детерминизм случайных решений). Не
  данные, а число.
- **архивный статический сид** (короткое имя — «статический сид», файлы
  `data/*.jsonl`) — кладовка готовых значений для генератора: браузеры,
  страны, устройства, метки кампаний. По
  [ADR-0006](./docs/adr/0006-generation-as-sole-analytics-source.md)
  он **выведен из аналитики и стал архивным**: витрины, дашборды и курс идут через
  startup-history/backfill → Kafka → STG → ODS → DDS → DM → Superset. Цель —
  **совсем убрать файл**, когда генератор научится придумывать фактуру сам
  (отдельная спека). Профиль ниже — теперь опорные цифры и список
  известных расхождений, а не эталон для подгонки (подгонять генерацию под сид
  число-в-число в ADR-0006 отклонено).
- **стартовая история стенда** (синонимы — **«стартовый сид»** и **«новый сид»**;
  это не новые значения слова, а та же сущность) — сгенерированное прошлое (заливка `K → ∞` +
  заморозка состояния), с которого живой стенд стартует непрерывно. По ADR-0006
  она **несущая**: именно с неё свежий стенд получает историю с первой минуты.
  Механизм реализован через Airflow DAG `world_init` и служебный чистый
  путь `make generated-history-analytics`; решение про часы — [ADR-0005](./docs/adr/0005-generator-model-clock.md).

### Мир (стенда)

Совокупное состояние данных стенда: события в Kafka, слои ClickHouse,
состояние генератора (модельные часы, живая популяция) и manifest с
контрольными числами. «Вырастить мир» — добавить в него модельное время
(`next-day` или живой поток), «восстановить мир» — залить его из артефакта.

### Эталонный мир (reference world)

Канонический стартовый мир менти: 3 модельных дня на профиле `daily-wave`,
собран мейнтейнером один раз, хранится сжатым артефактом в git. Все менти
импортируют один и тот же файл — числа в лабах воспроизводимы
число-в-число. Решение — [спека редизайна пути менти](./docs/specs/2026-07-19-mentee-path-redesign.md).

### Три режима менти

`import` (база: загрузить эталонный мир) и две ветки от восстановленного
состояния: `next-day` (пакетно добавить модельный день) и `continue`
(живой поток от той же границы). Это разные педагогики и разные лабы;
`backfill` — не режим менти, а инструмент мейнтейнера для сборки
эталонного мира. См. ту же спеку.

### Модельное время и масштаб (×K)

**Модельное время стенда** отвязано от настенных часов: генератор крутит
внутренние часы, а драйвер задаёт скорость — ×1 (как реальное время), ×K
(ускоренно, [учебная ручка в лабе 08](./docs/course/lessons/08_lab_continue.md#modelnoe-vremya)) или `K → ∞` (мгновенная заливка прошлого).
При ускорении «сейчас» стенда уходит вперёд настенного времени — это свойство, не
баг (ключ аналитики — `event_timestamp`). Решение и режимы —
[ADR-0005](./docs/adr/0005-generator-model-clock.md).

## Почему на статическом сиде `Unique Users == Unique Sessions`

В архивном статическом сиде (`data/*.jsonl`) каждый пользователь имеет **ровно один**
`click_id` — связь user↔визит строго 1:1 (проверено: 99 пользователей =
99 `click_id` в полном файле). Поэтому `uniqExact(user_domain_id)` и
`uniqExact(click_id)` дают одинаковое число.

Это **свойство конкретного датасета, а не закон модели и не баг расчёта.** В
реальных данных пользователь возвращается несколькими визитами, и числа
расходятся. Поэтому на дашборде мы **не** показываем две одинаковые KPI-плитки
(это читалось бы как ошибка) — вместо дубля идут производные метрики
(события на визит, доля визитов с одним событием), а различие «пользователь vs
сессия» объясняется текстом урока.

В аналитическом контуре это больше не опорный сценарий: генератор ведёт
популяцию пользователей и возвращения во времени.

## Профиль сид-датасета (измерено 2026-06-10, полные файлы)

Опорные цифры о статическом сиде (`data/*.jsonl`) — для калибровки генератора
и проверки гипотез. Измерено по **полным** файлам (1000 событий); внимание:
ранние оценки «1..7 событий на визит» делались по малому срезу и неверны.

- **Объём:** 1000 событий, 99 визитов (`click_id`), 99 пользователей (1:1).
- **Длина визита:** 1..27 событий, медиана 10, среднее 10.1.
- **Паузы между событиями визита:** медиана ~20 с, p95 ≈ 17 мин,
  максимум ≈ 40 мин; пауз длиннее 30 минут — 11 штук. Разброс времени внутри
  одного `click_id` — до 49 минут.
- **Воронка:** 25% визитов достигают `/confirmation`. Пути — с петлями:
  возвраты на `/home`, просмотр обоих товаров; у 21 из 25 «купивших» визитов
  есть события **после** `/confirmation`, у 9 — `/confirmation` встречается
  дважды. То есть `/confirmation` — последний *шаг воронки*, но не обязательно
  последнее *событие визита*.
- **Страницы (по событиям):** `/home` 426, `/product_a` 236, `/product_b` 157,
  `/cart` 93, `/payment` 53, `/confirmation` 35. `event_type` — 100% `pageview`.

## Слои данных

`STG → ODS → DDS → DM` — см. [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md).
Сейчас витрины (`dm.*`) и дашборд Superset строятся на статическом сиде. По
[ADR-0006](./docs/adr/0006-generation-as-sole-analytics-source.md) целевой источник
аналитики — генерация (стартовая история и живой поток); перевод загрузки, витрин
и дашбордов на неё входит в текущую работу, детальный план — отдельной спекой.
