Commit Graph
141 Commits
Author SHA1 Message Date
Dmitry Dementiev f0370cdb90 docs(generator): добавлены задачи реализации и handoff
- Зачем:
  - переработку steady-stream генератора нужно передать агентам как набор
    проверяемых вертикальных задач, а не как один крупный rewrite.
- Что:
  - создан локальный набор из семи ready-for-agent задач для реализации новой
    иерархической модели генератора.
  - добавлен handoff с текущим состоянием обсуждения, рекомендуемым следующим
    шагом через TDD и примером команды /goal для запуска задачи 01.
- Проверка:
  - git diff HEAD~1 --stat.
2026-06-11 10:48:37 +03:00
Dmitry DementievandClaude Fable 5 bcca8f5127 docs(generator): уточнена мат-спека по итогам ревью, handoff для передачи
- Зачем:
  - повторное адверсариальное ревью нашло ошибку в формуле межсессионной
    паузы (двойной счёт кулдауна) и незакрытый контракт публикации
    device/geo; дизайн-этап завершён, работа передаётся исполнителю.
- Что:
  - исправлена формула паузы (баланс цикла, минус длительность визита);
    зафиксированы каденция device/geo «на каждое событие, как в сиде»,
    правило выбора возвращающегося, стартовое распределение страниц,
    калибровка по медиане и среднему, инвариант потолков конфигурации,
    компактное хранение профиля ссылкой на сид-сессию.
  - уточнены критерии приёмки (среднее паузы вместо медианы, счёт шага
    «товары», имена полей времени) в обеих спеках.
  - добавлен handoff .scratch/handoffs/2026-06-10-generator-spec-to-codex.md
    (передача на детальный план/реализацию), отработавший handoff от
    2026-06-09 удалён.
- Проверка:
  - цифры спеки сверены замерами по полным data/*.jsonl (стартовые страницы
    58/24/17, шаги воронки 98>=94>=56>=35>=25, device 1000 строк / 99
    уникальных); повторное ревью свежим агентом блокеров не оставило.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 18:02:57 +03:00
Dmitry DementievandClaude Fable 5 0b5fc64f6f docs(agents): добавлено правило понятного русского языка
- Зачем:
  - ответы и документы агентов должны быть читаемы неспециалистом,
    без англицизмов и непереведённых слов.
- Что:
  - в AGENTS.md (раздел «Обязательные правила») добавлено требование к
    языку: понятный русский, устоявшиеся английские термины допустимы,
    сложные темы объяснять доступно.
- Проверка:
  - git diff AGENTS.md; правило видно в начале раздела обязательных правил.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 17:34:29 +03:00
Dmitry DementievandClaude Fable 5 6efa031023 docs(generator): добавлена мат-спека модели и исправлен профиль сида
- Зачем:
  - закрыть 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>
2026-06-10 17:32:47 +03:00
Dmitry DementievandClaude Opus 4.8 bce1ded9c4 docs(handoff): добавлен handoff по переработке генератора
- Зачем:
  - продолжить работу над генератором в новой сессии без потери контекста.
- Что:
  - .scratch/handoffs/2026-06-09-generator-rework.md: где остановились,
    ссылки на ADR/спеку, следующий шаг, suggested skills, состояние git.
- Проверка:
  - прочитать .scratch/handoffs/2026-06-09-generator-rework.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 18:04:08 +03:00
Dmitry DementievandClaude Opus 4.8 6ddc7a90d4 docs(generator): зафиксировано направление переработки генератора
- Зачем:
  - при возврате к генератору не переоткрывать выбор «генератор vs реплей»
    и иметь готовую рамку требований под реализацию steady-stream.
- Что:
  - ADR-0004: steady-stream питается синтетическим иерархическим генератором,
    не реплеем сида (обоснование + отклонённые варианты C/B).
  - спека docs/specs/2026-06-09: требования к иерархической модели сущностей
    и критерии приёмки; математика делегирована follow-up-спеке.
  - CONTEXT.md: термины «популяция пользователей», «возвращающийся пользователь».
- Проверка:
  - прочитать ADR-0004 и спеку; сверить термины в CONTEXT.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 18:04:00 +03:00
ddadminandDmitry Dementiev dd2c3cdaf9 docs(generator): зафиксирован дефект генеративной модели и план доработки
- Зачем:
  - генератор не влит и неочевидно почему; при возврате к нему легко
    переоткрывать заново вывод, что click_id на событие ломает семантику визита.
- Что:
  - добавлен KNOWN_ISSUES.md: модель интенсивности ок, модель сущностей неверна,
    план перехода на иерархию пользователь -> сессия -> событие.
  - в шапку README.md добавлено предупреждение со ссылкой на KNOWN_ISSUES.md.
- Проверка:
  - прочитать generator/KNOWN_ISSUES.md и сверить с generate_batch() в generator.py.
2026-06-09 17:27:17 +03:00
ddadminandDmitry Dementiev 40633602f5 docs(plans): добавлен план инкрементальной загрузки ETL v2
- Зачем:
  - нужно зафиксировать архитектуру перехода от full refresh к инкрементальной загрузке
  - план служит референсом для реализации и code review
- Что:
  - добавлен plans/incremental-etl-v2.md с полным описанием:
    * архитектура watermark (event_ts + lookback 5min)
    * DDL для meta.etl_watermarks_history с TTL 30 дней
    * SQL шаблоны для всех слоев (ODS, DDS, DM)
    * структура DAG с параллельной загрузкой ODS
    * функции get_watermark и save_watermark
    * алерты Grafana для late arrivals
    * демонстрация late arrivals через комментарии и логи
    * сценарии тестирования
    * оценка трудозатрат (15-16 часов)
- Проверка:
  - файл создан: plans/incremental-etl-v2.md
  - структура соответствует принятой архитектуре
  - все параметры согласованы (TTL, lookback, параллельность)
2026-06-09 17:27:17 +03:00
ddadminandDmitry Dementiev d97be5fa56 feat(monitoring): добавлен дашборд Grafana для мониторинга generator
- Зачем:
  - нужна визуализация метрик generator в реальном времени
  - Prometheus job уже настроен, не хватает Grafana dashboard
- Что:
  - добавлен provisioning-файл dashboards/generator-overview.json
  - 6 разделов: Overview, Events by Topic, Errors, Tick Statistics, Status, Info
  - Overview: Total Events/min (все 4 топика), Tick Duration (p50/p99)
  - Events by Topic: bar chart Events per Hour, Events Rate, Total Events
  - Errors: Total Errors, Error Rate, Errors by Topic (с 'or on() vector(0)')
  - Tick Statistics: Duration Distribution, Hour Factor (text), Tick Interval (text)
  - Status: Generator Status (threshold 120s), Generator Health (heartbeat), Time Since Last Tick
  - Info: команды и предупреждения о хардкоде GEN_TICK_SECONDS=5s
  - исправлены панели ошибок с 'or on() vector(0)' для корректного отображения 0
  - заменен heatmap на bar chart для стабильности
  - добавлены пояснения про Events/min = сумма 4 связанных топиков
  - Hour Factor синхронизирован с кодом генератора (00-05/09-18)
  - Generator Health: переименовано из State Management с value mappings
  - обновлены docs/OPERATIONS.md и generator/README.md
  - удален устаревший plans/generator-monitoring-plan.md
- Проверка:
  - дашборд открывается на http://localhost:3000/d/generator-overview
  - все панели отображают данные корректно (протестировано через Playwright)
  - ошибки показывают 0 вместо No data
  - Events/min корректно отображает сумму всех 4 топиков (~800-1000/min)
2026-06-09 17:27:17 +03:00
ddadminandDmitry Dementiev a70999d77a fix(generator): устранены риски стабильности из code review
- Зачем:

  - ревью выявило: фатальный старт при битом state, отсутствие retry в runtime

  - нужна graceful degradation и самовосстановление при сбоях Kafka

- Что:

  - GeneratorState.from_dict() теперь валидирует rng_state через setstate()

  - добавлен from_dict_safe() для graceful degradation (лог + start fresh)

  - KafkaPublisher: retry + reconnect в publish(), retry в flush()

  - KafkaBatchHistory: retry + reconnect в add(), retry в flush()

  - KafkaStateManager: retry в save(), load(), flush()

  - тесты: валидация state, graceful degradation, retry поведение

- Проверка:

  - make generator-test: 59 тестов проходят

  - docker compose restart generator - продолжает с tick=8 (was 6)

  - GEN_STATE_RESET=true - начинает с tick=1
2026-06-09 17:27:17 +03:00
ddadminandDmitry Dementiev e9a46e47ae fix(kafka): обновлено хранение state генератора без pickle
- Зачем:
  - упростить и сделать безопаснее сериализацию состояния генератора
  - повысить устойчивость старта при временной недоступности Kafka
- Что:
  - заменена сериализация rng state на JSON-safe формат без pickle/base64
  - добавлено восстановление tuple-структуры rng state после json
  - добавлен общий retry с exponential backoff для ensure_topics
  - обновлена документация по continuity и ограничениям после рестарта
  - расширены тесты state-сценариев и retry-логики
- Проверка:
  - make generator-test
  - 50 passed
2026-06-09 17:27:16 +03:00
ddadminandDmitry Dementiev 31e8901eb0 feat(generator): добавлено сохранение стейта между рестартами
- Зачем:

  - генератор должен продолжать работу с места остановки после падения/рестарта

  - нужно сохранять continuity тиков и состояние RNG для воспроизводимости

- Что:

  - добавлен GeneratorState dataclass (tick, rng_state, last_batch_id, timestamp)

  - добавлен KafkaStateManager для работы с compact topic generator_state

  - топик создаётся с cleanup.policy=compact (хранится только последнее значение)

  - интеграция в GeneratorService: восстановление при старте, сохранение после тика

  - новые env: GEN_STATE_ENABLED (по умолчанию true), GEN_STATE_RESET (по умолчанию false)

  - добавлены тесты test_state.py

  - обновлена документация README.md

- Проверка:

  - make generator-test (45 тестов проходят)

  - docker compose restart generator - продолжает с сохранённого tick

  - GEN_STATE_RESET=true - начинает с tick=1
2026-06-09 17:27:16 +03:00
ddadminandDmitry Dementiev ea114153b9 fix(generator): обработка findings из финального ревью
- Изолированы ошибки history-канала: best-effort с логированием, не валят тик
- Добавлено явное создание топика generator_batch_history при старте
- Добавлена защита от пустого словаря (ValueError при загрузке)
- Обновлена документация о структуре тестов
- Исправлены тесты на пустой словарь

Ревью: изоляция ошибок history, явное создание топика, защита от пустых данных
2026-06-09 17:27:16 +03:00
ddadminandDmitry Dementiev ffe81167c3 refactor(generator): удалён in-memory fallback для истории батчей
- Удалён класс InMemoryBatchHistory и вся fallback-логика
- Упрощён KafkaBatchHistory: убраны _initialized, get_stats(), обработка ошибок
- Обновлена документация (generator/README.md, docs/OPERATIONS.md)
- Упрощены тесты, удалены тесты для удалённого функционала
- Код стал честнее: без Kafka генератор падает при старте

Ревьюер: Prometheus даёт достаточно visibility, fallback избыточен
2026-06-09 17:27:16 +03:00
ddadminandDmitry Dementiev 731d991f94 refactor(generator): история batch в Kafka вместо ClickHouse
- Зачем:
  - ревью rev5: ClickHouse-интеграция была проблемной (порт 9000 native vs HTTP,
    неработающий fallback, отсутствие DDL для базы meta)
  - архитектурно чище: генератор остаётся pure Kafka producer,
    история доступна для аналитики через стандартный ingestion
- Что:
  - удален ClickHouseBatchHistory, clickhouse-connect зависимость
  - добавлен KafkaBatchHistory с записью в топик generator_batch_history
  - добавлен BatchRecord.to_dict() для JSON-сериализации
  - добавлен рабочий fallback: Kafka → InMemory при недоступности
  - удален pytest-asyncio (не использовался)
  - добавлены тесты test_kafka_history.py (15 тестов) и test_service.py (6 тестов)
  - обновлена документация: топик вместо таблицы ClickHouse
- Проверка:
  - make generator-test: 44/44 тестов пройдено
  - docker-compose валиден, генератор не зависит от clickhouse
2026-06-09 17:27:16 +03:00
ddadminandDmitry Dementiev 36ecbc62b1 test(generator): добавлен pytest и реорганизованы тесты
- Зачем:
  - были только standalone скрипты без системы запуска
  - нужна стандартная система тестирования для CI/CD
- Что:
  - добавлен pytest и pytest-asyncio в requirements.txt
  - создана директория tests/ с conftest.py (fixtures)
  - разделены тесты по модулям: test_config, test_generation, test_history
  - добавлены команды в Makefile: generator-test, generator-test-build, generator-test-cov
  - удалены устаревшие test_local.py и test_comprehensive.py
  - обновлена документация в README.md
- Проверка:
  - make generator-test — 23/23 тестов пройдено
2026-06-09 17:27:16 +03:00
ddadminandDmitry Dementiev 04541677ff feat(generator): доработка по ревью rev5 — тики, метрики, история
- Зачем:
  - ревью rev5 выявило несоответствие плану: дефолт 60s против 5s,
    неработающий jitter, отсутствие Prometheus-метрик и персистентности
- Что:
  - дефолт GEN_TICK_SECONDS изменён с 60s на 5s (steady-stream режим)
  - реализован GEN_JITTER_PCT в расчёте объёма тика (вариативность)
  - добавлены Prometheus метрики: generator_events_total,
    generator_publish_errors_total, generator_tick_duration_seconds,
    generator_last_success_timestamp (порт 9109)
  - добавлен ClickHouseBatchHistory с записью в meta.generator_batches
  - lazy import kafka-python для тестов без Kafka
  - обновлён scrape_config в configs/prometheus.yml
  - удалён нерабочий verify_kafka.py
- Проверка:
  - test_comprehensive.py: 9/9 тестов пройдено
  - docker build -t generator:rev5 . — успешно
  - docker-compose.yml валиден
2026-06-09 17:27:01 +03:00
ddadminandDmitry Dementiev e8d1c9efa9 feat(infra): добавлен автономный генератор событий для Kafka
- Зачем:
  - нужен постоянный поток данных для демонстрации работы стека
  - текущий batch-загрузчик не позволяет показать streaming-сценарии
- Что:
  - добавлен сервис generator с режимом steady (Poisson-интенсивность)
  - генератор публикует в 4 топика: browser/location/device/geo_events
  - сохраняются связи event_id и click_id между событиями
  - сборка через uv для скорости и компактности образа
  - добавлены команды generator-* в Makefile
  - комплексные тесты: валидация, статистика, формат сообщений
- Проверка:
  - `docker run --rm -v $(pwd)/..:/workspace -w /workspace/generator generator:test python test_comprehensive.py` — 8/8 тестов
  - `make generator-up` — 3 тика без ошибок, отправлено 2904 сообщения
2026-06-09 17:27:01 +03:00
ddadminandDmitry Dementiev 7c6cfd7d18 docs(docs): обновлён план генератора по интеграции Prometheus
- Зачем:
  - зафиксировать решение об observability генератора на уровне MVP-плана
- Что:
  - добавлены требования по /metrics, scrape_config и target generator:9109
  - добавлен env-параметр GEN_METRICS_PORT
  - обновлены шаг внедрения и критерии успеха
- Проверка:
  - проверен diff только для plans/generator_demo_stream_plan.md
2026-06-09 17:26:31 +03:00
ddadminandDmitry Dementiev cbc2f72871 docs(docs): актуализировано ТЗ и потоки ingest
- Зачем:
  - убрать рассинхрон между кратким ТЗ, архитектурой и планом генератора
- Что:
  - сокращен docs/DE-task.md до формата краткого ТЗ проекта
  - обновлены docs/ARCHITECTURE.md и README.md: bootstrap через kafka_load и steady-stream через generator-service
  - обновлен plans/generator_demo_stream_plan.md: режим steady-stream и тик-публикация
- Проверка:
  - просмотрен git diff по измененным файлам
  - в коммит включены только мои документационные изменения
2026-06-09 17:26:31 +03:00
ddadminandDmitry Dementiev 8d0c8f46fd docs(docs): обновлен план простого автономного генератора
- Зачем:
  - зафиксировать реалистичный MVP без переусложнения
- Что:
  - оставлен один режим steady для автономного генератора
  - добавлена минимальная статистическая модель потока на базе Poisson
  - уточнены минимальные метрики, история batch и короткий roadmap внедрения
- Проверка:
  - проверен diff и итоговое содержимое plans/generator_demo_stream_plan.md
2026-06-09 17:25:17 +03:00
ddadminandDmitry Dementiev 4fbe82e74c docs(docs): add plan for long-running demo data generator
- Why:
  - define a clear architecture for continuous demo data generation
  - ensure visual analytics with realistic scenario-based behavior
- What:
  - add a standalone plan with target architecture and components
  - define demo_visible_v1 scenarios, KPI ranges, and DQ behavior
  - describe Airflow orchestration, observability, rollout stages, and acceptance criteria
- Check:
  - reviewed document structure and consistency in plans/
2026-06-09 17:25:17 +03:00
ddadmin 20184c9e18 Merge ветки docs/advanced-clickstream-course в main
- Зачем:
  - фича готова: продвинутый курс (уроки 0–6), редизайн Superset, гейт целостности
    DDS, мониторинг и выверенные по коду профильные доки. Codex работу завершил.
- Что:
  - --no-ff merge ветки docs/advanced-clickstream-course.
  - артефакты .scratch/ (handoff'ы, аудит) намеренно исключены из дерева main.
- Проверка:
  - git ls-tree -r HEAD не содержит .scratch; git show --summary HEAD — два родителя.
2026-06-06 22:08:58 +03:00
ddadmin 9e660eaf98 docs(handoff): зафиксировано закрытие аудита точности доков
- Зачем:
  - следующей сессии нужна точка опоры: что сделано, какой канон у слоёв и какие
    хвосты остались вне скоупа.
- Что:
  - добавлен .scratch/handoffs/2026-06-06-docs-accuracy-done.md.
  - зафиксированы рамка путей (Airflow — основной, scripts/make — запасной),
    канон по урокам 2–3 и открытые хвосты (лицензия, непроверенные уроки 0,1,4–6).
- Проверка:
  - git show --stat HEAD; ссылки на findings.md и коммит 92e9c4b актуальны.
2026-06-06 21:45:52 +03:00
ddadmin 92e9c4b45a docs(accuracy): профильная документация выверена по коду
- Зачем:
  - профильные доки отстали от реализации: схема ods.*_errors, DQ-split и
    сборка dds.event описывались неверно, ряд артефактов и параметров отсутствовал.
    Канон по этим темам де-факто задают свежие уроки 2–3 курса.
- Что:
  - ARCHITECTURE: ods.*_errors как копия с Kafka-метаданными+raw+error_reason;
    DQ-split подан как пересекающийся; dds.event — browser-driven LEFT JOIN с
    маркером location_not_found; добавлен перечень DQ-маркеров; уточнены
    dq_summary (слой dm, orphan_events) и v_session_overview.
  - REPO_MAP: добавлен sql/ods/20_stg_to_ods.sql, утилиты DAG, скрипты Superset;
    scripts/make помечены как запасной путь, Airflow — основной.
  - OPERATIONS: параметр wait_stg_timeout_sec; порт Superset и креды ClickHouse.
  - SUPERSET_DASHBOARD: исправлен пароль ClickHouse (123456); убран сломанный
    make superset-export, удалён superset/export_dashboard.py и target в Makefile.
- Проверка:
  - git diff проверен против sql/*, airflow/dags/*, configs/default_user.xml;
    ER-диаграмма провалидирована mermaid-валидатором.
2026-06-06 21:43:31 +03:00
ddadmin 90f3ac5ea1 docs(handoff): контекст для уточнения документации по архитектуре
- Зачем:
  - следующая сессия чинит профильные доки, отставшие от кода; нужен
    быстрый вход с готовым рабочим списком, а отработанный handoff про
    корневой README больше не актуален.
- Что:
  - добавлен handoff 2026-06-06-docs-accuracy-fixes.md со ссылкой на
    аудит, порядком починки и ключевым контекстом.
  - удалён отработанный 2026-06-06-root-readme-polish.md.
- Проверка:
  - открыть .scratch/handoffs/2026-06-06-docs-accuracy-fixes.md и
    .scratch/docs-accuracy-audit/findings.md.
2026-06-06 20:17:44 +03:00
ddadmin 5bd215d19d docs(audit): зафиксирован аудит точности профильной документации
- Зачем:
  - при переработке README выяснилось, что профильные доки местами
    отстали от кода; находки нужно сохранить как отдельную задачу, чтобы
    не потерять и чинить отдельным проходом.
- Что:
  - добавлен .scratch/docs-accuracy-audit/findings.md со сверенными с
    кодом расхождениями ARCHITECTURE, OPERATIONS, REPO_MAP,
    SUPERSET_DASHBOARD (с привязкой к файлам и строкам).
  - находки разнесены по серьёзности и снабжены порядком починки.
- Проверка:
  - открыть .scratch/docs-accuracy-audit/findings.md; сверить 🔴-пункты
    с указанными строками кода.
2026-06-06 20:11:51 +03:00
ddadmin ce7f03be28 docs(readme): корневой README переписан под менти и песочницу
- Зачем:
  - стенд теперь учебный (для менти и для экспериментов), рекрутерская
    рамка DE-задания неактуальна и сбивала читателя; README дублировал
    профильные доки и расходился с ними.
- Что:
  - README сделан тонким указателем на три двери: курс, быстрый старт,
    устройство стенда; объём сокращён с 361 до 96 строк.
  - быстрый старт переведён на основной Airflow-путь (ddl_init →
    kafka_load → etl_pipeline) вместо legacy make-пути.
  - срезаны дубли (DBeaver, структура дашборда, мониторинг, troubleshooting,
    Makefile, дерево проекта, «Статус/В планах») с уводом в OPERATIONS,
    ARCHITECTURE, REPO_MAP, SUPERSET_DASHBOARD.
  - исправлен URL дашборда Superset на slug ecommerce-analytics;
    убран фейковый бейдж лицензии.
- Проверка:
  - открыть README.md, пройти быстрый старт, проверить рендер mermaid и
    рабочие ссылки на профильные доки.
2026-06-06 20:11:38 +03:00
ddadmin d4e6d84524 docs(handoff): контекст для переработки корневого README
- Зачем:
  - следующая сессия продолжает работу над документацией с фокусом на
    корневой README; нужен контекст (модель курса, голос, подходы), а не
    чек-лист задач.
- Что:
  - добавлен .scratch/handoffs/2026-06-06-root-readme-polish.md: модель
    курса, линза mentee-first, рабочие подходы, состояние git и рабочего
    дерева, направление по корневому README (без предписаний).
- Проверка:
  - чистый .md, прогон стенда не нужен.
2026-06-06 19:06:29 +03:00
ddadmin 2f905e4c73 docs(course): README курса переписан от менти + крючок менторства
- Зачем:
  - прежний README вёл читателя в авторские доки (PRD/LEARNING_PLAN/
    LESSON_STANDARD), а менти нужна точка входа: с чего начать, как ходить
    по урокам и как поднять стенд. Цель PRD — самодостаточный материал.
- Что:
  - mentee-first структура: «что нужно до старта» (make up → ddl →
    LIMIT=50 make data, совпадает с уроками и правилом малого среза),
    индекс уроков 0–6 со ссылками и режимом, «как проходить».
  - блок-крючок «сам / с ментором» в тон роадмапа + CTA в Telegram.
  - авторские доки убраны в секцию «Под капотом курса».
- Проверка:
  - все 11 внутренних ссылок резолвятся; ai-text-lint чист (house style сохранён).
2026-06-06 19:06:16 +03:00
ddadmin bae1e02240 docs(superset): уточнена область фильтров dashboard
- Зачем:
  - нужно снять двусмысленность между native filters и click-to-filter в Superset dashboard.
- Что:
  - описана фильтрация через левую панель Superset.
  - уточнена область действия фильтров по совместимым charts и DM-витринам.
  - зафиксировано, что click-to-filter между виджетами не включен.
- Проверка:
  - git diff --check -- README.md docs/SUPERSET_DASHBOARD.md docs/course/lessons/06_superset_bi.md.
2026-06-06 18:50:50 +03:00
ddadmin d98ae9c48a docs(course): финальный ai-text-lint, синхронизация PRD §7 и уборка handoff'ов
- Зачем:
  - финализация подготовки уроков: пройти обязательный QA-шаг
    (ai-text-lint по LESSON_STANDARD §2), привести PRD к факту и убрать
    отработанные handoff'ы.
- Что:
  - урок 4: убран AI-маркер S01 («не только… но и» → «и… и») по итогам
    прогона ai-text-lint; остальные 6 уроков чисты от маркеров.
  - PRD §7: закрыты устаревшие открытые вопросы (глубина урока 5, Superset),
    оставлен только реальный пункт — ретроспектива после первого прогона.
  - удалены 3 отработанных handoff'а в .scratch/handoffs/.
- Проверка:
  - git show --stat HEAD; визуальная сверка PRD §7 и урока 4.
2026-06-06 18:41:15 +03:00
ddadmin 589c556b17 docs(course): сквозной ревью — правки консистентности уроков 2/3/5 и OPERATIONS
- Зачем:
  - сквозной ревью курса нашёл расхождения учебного текста с реальным выводом
    стенда и один баг в операторских доках — менти увидел бы не то, что в уроке.
- Что:
  - урок 2: порядок строк «Статистики ODS» выровнен под фактический вывод
    run_batch.sh (4 основных таблицы, затем 4 *_errors); снято «по строчкам».
  - урок 3: добавлено пояснение, что check_date — это today() из витрины
    (у менти будет своя дата, не как в примере).
  - урок 5: «должно быть не в Alerting» → «в состоянии Normal (не Alerting)».
  - OPERATIONS.md: несуществующий FULL=1 заменён на реальный knob LIMIT=50
    (по умолчанию полный объём — подтверждено load_kafka_data.sh:27,128).
- Проверка:
  - git diff показывает 4 файла, +9/-6; grep 'FULL=' по docs/ пуст.
  - порядок таблицы сверен с run_batch.sh:111-118; today() — sql/dm/40_dds_to_dm.sql:105.
2026-06-06 18:33:14 +03:00
ddadmin bbd5784e2a docs(course): синхронизирован LEARNING_PLAN с фактом — правки §3.1 сделаны
- Зачем:
  - все 11 чекбоксов §3.1 по урокам 2–3 были `[ ]`, хотя правки давно
    в коде/уроках; план вводил в заблуждение «работа не сделана».
- Что:
  - проставлены `[x]` по урокам 2 и 3 после сверки с реальным кодом
    (шапки «поток данных», DQ-split «зачем», чистка legacy-MV, демоут DM,
    seed 1919, war-story kafka_ts, recap цепочки).
  - в §4 добавлена строка статуса: уроки 0–6 написаны, контент собран.
- Проверка:
  - grep '\[ \]' docs/course/LEARNING_PLAN.md  # незакрытых пунктов §3.1 нет
2026-06-06 18:14:07 +03:00
ddadmin 24f538e6f4 docs(superset): синхронизирован урок 6 с дашбордом
- Зачем:
  - урок 6 должен совпадать с текущей конфигурацией Superset и не вводить в заблуждение по metadata store.
- Что:
  - URL дашборда в уроке переведен на стабильный slug ecommerce-analytics.
  - сниппет Page Funnel помечен как фрагмент с ключевыми полями, а не полный params.
  - устаревший комментарий про SQLite заменен на PostgreSQL metadata store.
- Проверка:
  - python3 -m py_compile superset/init_superset.py superset/create_dashboard.py.
  - git diff --check.
2026-06-06 18:12:06 +03:00
ddadmin 2bd4087e4a docs(handoff): задача по консистентности код-сниппетов урока 6
- Зачем:
  - дашборд за сессию менялся трижды; остался зазор — в §3 урока 6 сниппет
    Page Funnel показывает урезанный params без многоточия. Правку выносим в
    отдельную сессию, чтобы не раздувать контекст текущей.
- Что:
  - добавлен handoff с задачей (сниппет Page Funnel + сквозная сверка сниппетов
    §3), контекстом запушенных коммитов и git-гигиеной.
- Проверка:
  - следующая сессия сверяет сниппеты урока с superset/create_dashboard.py.
2026-06-06 18:06:16 +03:00
ddadmin bf940cc249 docs(course): пункт интро урока 6 выровнен под row-lineage
- Зачем:
  - после замены DQ-чарта на row-lineage в списке «на какие вопросы отвечает
    BI» остался повисший пункт «есть ли видимые проблемы качества данных» —
    чарта, который на него отвечал, больше нет.
- Что:
  - пункт переформулирован под актуальный чарт Rows by Layer
    («доходят ли строки до витрины без потерь по слоям конвейера»).
- Проверка:
  - сквозная вычитка урока 6: состав чартов, имена и числа согласованы.
2026-06-06 18:01:34 +03:00
ddadmin c9300e7d5d fix(superset): 5-минутные бакеты вместо часовых в графике динамики
- Зачем:
  - все события стенда укладываются в ~50 минут (20:51–21:41 28.11.2022),
    поэтому часовая гранулярность давала всего 2 точки и прямую диагональ,
    которая читалась как ошибка расчёта и ничему не учила менти.
- Что:
  - time_grain_sqla переведён с PT1H на PT5M (~10 точек, реальная форма трафика).
  - чарт переименован «Events by Hour» → «Events over Time» (идемпотентно через
    previous_slice_names), т.к. «by Hour» противоречит 5-минутным бакетам.
  - синхронизированы README, SUPERSET_DASHBOARD.md и урок 6.
- Проверка:
  - python3 -m py_compile superset/create_dashboard.py.
  - make superset-dashboard (идемпотентно, чарт ID 5 переименован, 10 чартов).
  - визуально через playwright-cli: кривая ~11 точек 20:50–21:40, консоль чистая.
2026-06-06 17:58:50 +03:00
ddadmin 2563c79082 docs(superset): синхронизация доков и урока 6 под row-lineage
- Зачем:
  - после смены чарта на row-lineage пользовательская дока, README и урок 6
    описывали несуществующий «Data Quality Summary» и старый состав KPI;
    термин «зерно (grain)» использовался без пояснения.
- Что:
  - SUPERSET_DASHBOARD.md, README, урок 6 описывают «Rows by Layer (event)»,
    выровнен состав KPI/чартов; термин «зерно» поясняется в уроке простыми
    словами с якорем из данных (события 1000 / визиты 99).
  - термин выровнен на «визит» по CONTEXT.md (click_id = визит/сессия).
  - в спеку редизайна добавлена секция «Пересмотр после приёмки» как след решения.
- Проверка:
  - grep по «Data Quality Summary»/«Row Count» вне handoffs пуст.
  - визуальная вычитка изменённых разделов.
2026-06-06 17:49:01 +03:00
ddadmin 281d9d25c9 feat(superset): честный row-lineage по слоям вместо ложной DQ-воронки
- Зачем:
  - чарт «Data Quality Summary» суммировал total_rows по всем таблицам слоя,
    складывал таблицы разного зерна (события 1000 + визиты 99 + error-таблицы 0)
    и рисовал убывающую «воронку потерь» (stg≈4250→ods≈2198→dds≈1099), которой
    в данных нет. На учебном стенде это активно вводит в заблуждение.
- Что:
  - чарт переделан в row-lineage одного event-зерна и переименован в
    «🧱 Rows by Layer (event)»; rename идемпотентный через previous_slice_names.
  - чарт берёт по одной канонической таблице на слой
    (browser_raw→browser_event→event→v_events_enriched), порядок слоёв задан
    числовым префиксом в groupby + order_bars.
  - в dm.dq_summary добавлена строка total_rows для слоя dm, чтобы цепочка
    замыкалась до витрины.
  - описание дашборда обновлено под новый смысл.
- Проверка:
  - python3 -m py_compile superset/create_dashboard.py.
  - make transform / прогон sql/dm/40_dds_to_dm.sql; в dq_summary есть строка dm.
  - make superset-dashboard (идемпотентно, 10 чартов, дублей нет).
  - визуально через playwright-cli: 4 столбца 1·stg→2·ods→3·dds→4·dm,
    видимый шаг дедупликации 1050→1000, консоль без ошибок.
2026-06-06 17:48:43 +03:00
ddadmin 58df1d55c4 docs(superset): исходный handoff помечен как выполненный
- Зачем:
  - редизайн реализован и принят; старый handoff «иди реализуй» вводил в заблуждение.
- Что:
  - в .scratch/handoffs/2026-06-06-superset-dashboard-redesign.md добавлен баннер
    СТАТУС: ВЫПОЛНЕНО со ссылкой на -implemented.md.
- Проверка:
  - файл открывается баннером, ниже историческая постановка.
2026-06-06 17:04:53 +03:00
ddadmin 1bec6bb8ad feat(superset): обновлен состав KPI и воронки дашборда
- Зачем:
  - нужно убрать дублирующий KPI Unique Sessions и сделать эталонный dashboard честнее для учебного анализа.
- Что:
  - обновлены KPI, добавлена Conversion to /confirmation и Page Funnel.
  - добавлена идемпотентная миграция старых chart names без дублей.
  - синхронизированы документация, урок 6 и спека редизайна.
  - добавлен handoff для продолжения работы в новой сессии.
- Проверка:
  - python3 -m py_compile superset/create_dashboard.py.
  - make superset-dashboard.
  - Superset metadata: dashboard_charts=10, obsolete_unique_sessions=0, page_funnel_type=funnel.
2026-06-06 17:00:02 +03:00
ddadmin 0fd8a08667 docs(superset): в handoff добавлен разрез приёмки для Codex
- Зачем:
  - Codex силён в реализации, но визуальную приёмку дашборда не вытянет —
    нужно явно оставить screenshot sign-off человеку/vision-агенту.
- Что:
  - в handoff добавлен блок «Если задачу берёт Codex»: не визуальные само-проверки
    его, визуальный sign-off — отдельно.
- Проверка:
  - .scratch/handoffs/2026-06-06-...md содержит блок и не закрывает done по визуалу.
2026-06-06 16:17:34 +03:00
ddadmin 7c7e9e5a7c docs(superset): спека редизайна дашборда и handoff
- Зачем:
  - дашборд-эталон показывал две одинаковые KPI-плитки; нужен честный состав метрик
    на полных данных, зафиксированный до реализации.
- Что:
  - docs/specs/2026-06-06-...: KPI Events/Users/Avg per Visit/Conversion, Top Pages → Funnel, триаж чартов.
  - .scratch/handoffs/2026-06-06-...: handoff для реализации в новой сессии.
- Проверка:
  - числа спеки сверены с прямым запросом в ClickHouse на полном датасете.
2026-06-06 16:12:10 +03:00
ddadmin 79481a9351 docs(context): глоссарий домена кликстрима
- Зачем:
  - зафиксировать доменный язык, чтобы метрики дашборда и урок 6 опирались на единые термины.
- Что:
  - добавлен CONTEXT.md: пользователь/визит-сессия/событие, иерархия, почему на демо Users == Sessions.
- Проверка:
  - термины сверены с sql/ddl/dds/30_dds.sql и sql/ddl/dm/40_dm.sql.
2026-06-06 16:12:10 +03:00
ddadmin 18a55dd640 docs(adr): спеки в docs/specs, handoff'ы в .scratch/handoffs
- Зачем:
  - воркфлоу эволюционировал: design-спекам нужен durable-дом, а handoff'ам —
    стабильное место вместо эфемерного /tmp.
- Что:
  - ADR-0002: design-спеки переезжают в docs/specs/YYYY-MM-DD-*.md (superseding ADR-0001).
  - ADR-0003: handoff'ы — одноразовые леса́ в .scratch/handoffs/, коммитятся, уборка best-effort.
  - ADR-0001 помечен как частично заменённый; AGENTS.md описывает место handoff'ов.
- Проверка:
  - docs/adr/000{1,2,3} согласованы, перекрёстные ссылки рабочие.
2026-06-06 16:12:10 +03:00
ddadmin 0dd88183b7 chore(git): игнорировать артефакты playwright-cli/mcp
- Зачем:
  - артефакты браузерной автоматизации не должны попадать в индекс.
- Что:
  - добавлены .playwright-cli и .playwright-mcp в .gitignore.
- Проверка:
  - git status не показывает .playwright-cli/ после прогона playwright-cli.
2026-06-06 16:12:10 +03:00
ddadmin f1fc31fa3f fix(superset): починена ROW-раскладка дашборда и честные KPI
- Зачем:
  - дашборд рендерился одной колонкой во всю ширину, а KPI показывали
    значение последнего часового бакета (1/1/1) вместо итогов по срезу.
- Что:
  - чарты разложены по строкам-контейнерам ROW (Superset layout v2):
    KPI-полоса 4-в-ряд + аналитические блоки парами вместо плоского
    списка CHART под GRID с игнорируемыми x/y.
  - KPI переведены с big_number на big_number_total без granularity_sqla;
    sync_query_context чистит granularity/time_grain для тотала.
- Проверка:
  - make superset-dashboard; GET /api/v1/dashboard/1/datasets → 200;
    position_json содержит 4 ROW; KPI показывают 50/26/26/1.92.
2026-06-05 22:56:53 +03:00
ddadmin 9f69a33c31 fix(superset): исправлен BI-дашборд и добавлен урок 6
- Зачем:
  - Superset dashboard открывался с ошибками datasources и неудобным layout, а курс не содержал готового урока по BI-витрине.
- Что:
  - добавлен урок 6 про Superset поверх ClickHouse DM-витрин.
  - исправлена раскладка dashboard и дефолтный фильтр даты для исторических демо-данных.
  - добавлено восстановление metadata колонок датасетов при обновлении dashboard.
- Проверка:
  - make superset-dashboard.
  - /api/v1/dashboard/1/datasets и /superset/explore_json для chart 10 возвращают 200.
  - python3 -m py_compile superset/create_dashboard.py; git diff --cached --check.
2026-06-05 22:30:19 +03:00
ddadmin 5f5312c70c fix(dds): починены мёртвые проверки *_not_found + правки урока 3 по ревью
- Зачем:
  - перечитка урока 3 свежим взглядом нашла баг в его эталонном пути: проверки
    device_not_found/geo_not_found/location_not_found в DDS никогда не срабатывали,
    а текст урока ошибочно утверждал, что метки ставятся
- Что:
  - sql/dds/30_ods_to_dds.sql: добавлен SETTINGS join_use_nulls=1 в оба
    INSERT...SELECT. Без него LEFT JOIN на несовпадении клал в assumeNotNull(click_id)
    нулевой UUID (не NULL), и if(...IS NULL, ['*_not_found'], []) молча давал []
    (мёртвый код). Тот же класс бага про типы/NULL, что kafka_ts в уроке 1
  - docs/course/lessons/03_ods_to_dds.md: убраны ложные claim'ы про geo_not_found/
    location_not_found, формулировки приведены к реальному поведению (клик без гео
    остаётся с пустыми полями NULL; целостность событий — через orphan_events);
    поправлена опечатка «список всех клиентов» → «всех кликов»
- Проверка:
  - синтетический тест join_use_nulls=1: клик в device без geo → в ods_parse_errors
    появляются geo_not_found и geo_country_missing (до фикса — пусто)
  - LIMIT=50 make transform после фикса: dds.click=26, dds.event=50,
    orphan_events=0, ни одной строки с непустым ods_parse_errors (вывод не изменился —
    на чистом срезе несовпадений нет)
2026-06-05 21:58:44 +03:00