Зачем: два слепых ревью (Codex CODE-1..9, Claude TASK-1..2) и перепроверки нашли дефекты в лабах и метадоках; финал лабы 08 переделан по решению пользователя. Что: - канонический сброс в README курса теперь снимает DAG'и с паузы (все создаются на паузе); - имя дашборда исправлено на «E-commerce Analytics Dashboard»; - финал лабы 08: вместо мифа «users == sessions на статике» — вернувшийся пользователь через границу заморозки и измеренное обещание свежести; §2 велит записать границы и время (§6 их требует); - CONTEXT.md: эталонный мир — замороженный живой, 4 056 пользователей / 26 083 визита, возвраты уже есть; - уроки 5–6 ведут в обязательный маршрут, живое упражнение урока 5 требует канонический сброс; - контрактные тесты: убран якорь на удалённую команду; добавленные на триаже тесты-цитаты срезаны до устойчивых инвариантов (прозаический легаси-жанр — issue #24); - handoff обновлён до текущего состояния. Проверка: make test (219 generator + 31 contract) и make lint зелёные; SQL вернувшегося пользователя проверен на эфемерном ClickHouse 25.1 (на полном наборе — в #23). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
13 KiB
CONTEXT.md — глоссарий домена
Доменный язык стенда: как мы называем сущности кликстрима и что под ними
понимаем. Один термин — одно имя. Ведётся вместе с docs/adr/ (см.
ADR-0001).
Сущности
Пользователь (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).
Важно: в источнике нет отдельного 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,
форма доработки — спека генератора.
Популяция пользователей (user population)
Множество пользователей с постоянными user_domain_id, которые генератор
держит во времени и из которых разыгрывает активность. В отличие от сида (где
пул user_domain_id плоский и 1:1 с визитами), популяция — это источник
возвратов: один и тот же пользователь порождает несколько визитов.
Возвращающийся пользователь (returning user)
Пользователь, открывающий более одного визита (click_id) во времени, с
межсессионными паузами. Эталонный мир уже содержит возвраты: это замороженный
LIVE-мир с 4 056 пользователями и 26 083 визитами, поэтому уже при импорте
выполняется users < sessions. Режим continue продолжает этот мир: итоги
растут дальше и зависят от длительности запуска у каждого менти.
Три значения слова «сид»
Слово перегружено — в разговоре про генератор это три разные сущности, их нельзя путать (см. ADR-0005):
GEN_SEED— зерно ГПСЧ генератора (детерминизм случайных решений). Не данные, а число.- архивный статический сид (короткое имя — «статический сид», файлы
data/*.jsonl) — кладовка готовых значений для генератора: браузеры, страны, устройства, метки кампаний. По ADR-0006 он выведен из аналитики и стал архивным: витрины, дашборды и курс идут через startup-history/backfill → Kafka → STG → ODS → DDS → DM → Superset. Цель — совсем убрать файл, когда генератор научится придумывать фактуру сам (отдельная спека). Профиль ниже — теперь опорные цифры и список известных расхождений, а не эталон для подгонки (подгонять генерацию под сид число-в-число в ADR-0006 отклонено). - стартовая история стенда (синонимы — «стартовый сид» и «новый сид»;
это не новые значения слова, а та же сущность) — сгенерированное прошлое (заливка
K → ∞+ заморозка состояния), с которого живой стенд стартует непрерывно. По ADR-0006 она несущая: именно с неё свежий стенд получает историю с первой минуты. Механизм реализован через Airflow DAGworld_initи служебный чистый путьmake generated-history-analytics; решение про часы — ADR-0005.
Мир (стенда)
Совокупное состояние данных стенда: события в Kafka, слои ClickHouse,
состояние генератора (модельные часы, живая популяция) и manifest с
контрольными числами. «Вырастить мир» — добавить в него модельное время
(next-day или живой поток), «восстановить мир» — залить его из артефакта.
Эталонный мир (reference world)
Канонический стартовый мир менти: 3 модельных дня на профиле daily-wave,
собран мейнтейнером один раз, хранится сжатым артефактом в git. Все менти
импортируют один и тот же файл — числа в лабах воспроизводимы
число-в-число. Решение — спека редизайна пути менти.
Три режима менти
import (база: загрузить эталонный мир) и две ветки от восстановленного
состояния: next-day (пакетно добавить модельный день) и continue
(живой поток от той же границы). Это разные педагогики и разные лабы;
backfill — не режим менти, а инструмент мейнтейнера для сборки
эталонного мира. См. ту же спеку.
Модельное время и масштаб (×K)
Модельное время стенда отвязано от настенных часов: генератор крутит
внутренние часы, а драйвер задаёт скорость — ×1 (как реальное время), ×K
(ускоренно, учебная ручка в лабе 08) или K → ∞ (мгновенная заливка прошлого).
При ускорении «сейчас» стенда уходит вперёд настенного времени — это свойство, не
баг (ключ аналитики — event_timestamp). Решение и режимы —
ADR-0005.
Почему на статическом сиде 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— последний шаг воронки, но не обязательно последнее событие визита. - Страницы (по событиям):
/home426,/product_a236,/product_b157,/cart93,/payment53,/confirmation35.event_type— 100%pageview.
Слои данных
STG → ODS → DDS → DM — см. docs/ARCHITECTURE.md.
Сейчас витрины (dm.*) и дашборд Superset строятся на статическом сиде. По
ADR-0006 целевой источник
аналитики — генерация (стартовая история и живой поток); перевод загрузки, витрин
и дашбордов на неё входит в текущую работу, детальный план — отдельной спекой.