Commit Graph
100 Commits
Author SHA1 Message Date
ddadmin d35254ead6 feat(stand): переведён аналитический путь на стартовую историю
- Зачем:
  - чистый стенд должен строить аналитику из генерации, а не из архивного JSONL-сида.
- Что:
  - добавлены команды generated-history-analytics и generated-history-check.
  - обновлены README, operations и Superset-документы под путь generator backfill -> DM -> Superset.
  - создан follow-up на миграцию учебных материалов с архивного сида.
- Проверка:
  - make generated-history-analytics.
  - make generated-history-check.
  - reviewer gate issue 06 пройден без блокирующих находок.
2026-06-14 20:22:17 +03:00
ddadmin d5408f28e9 feat(generator): добавлена стартовая история через backfill
- Зачем:
  - стенду нужна повторяемая история с живым продолжением от модельной границы без дублей и разрыва визитов.
- Что:
  - добавлен backfill-режим с `GEN_MODEL_T_END`, manifest и state на `T_end`.
  - live-запуск восстанавливается из manifest без настенной дельты и проверяет совместимость state.
  - добавлены SQL-проверки формы данных, повторяемости и стыка backfill с live.
- Проверка:
  - make generator-test.
  - два чистых ClickHouse-прогона backfill дали одинаковые manifest checksums и digest.
  - reviewer gate issue 05 пройден после исправлений state/manifest.
2026-06-14 19:45:58 +03:00
ddadmin fcb06da16e feat(generator): добавлено восстановление state по модельному времени
- Зачем:
  - рестарт генератора должен продолжать поток от модельной точки без дублей и смешивания state разных настроек.
- Что:
  - state v2 хранит модельную и настенную метки, скорость, timezone, T0 и seed.
  - live-восстановление считает модельную точку по настенной дельте и проверяет совместимость config.
  - добавлен путь восстановления от T_end и тесты короткого и долгого простоя.
- Проверка:
  - make generator-test.
  - ClickHouse-сценарии короткого и долгого восстановления state.
  - reviewer gate issue 04 пройден после исправления совместимости state.
2026-06-14 18:47:34 +03:00
ddadmin 589e2321b3 feat(generator): добавлено ускорение модельного времени
- Зачем:
  - ускоренный стенд должен проходить больше модельного времени и давать соответствующий событийный бюджет.
- Что:
  - расчёт интенсивности переведён на модельную длительность тика.
  - добавлена устойчивая выборка бюджета при больших λ.
  - усилены тесты ×K, дневного коэффициента и независимости от настенного часа.
- Проверка:
  - make generator-test.
  - review gate после issue 03 пройден после исправления underflow Poisson.
2026-06-14 17:48:51 +03:00
ddadmin efb07b0283 feat(generator): добавлено модельное время live-потока
- Зачем:
  - генератор должен писать события от модельной точки T0 и проверяться повторяемо в ClickHouse.
- Что:
  - добавлены настройки модельного времени и передача модельной точки в live-тик.
  - дневной коэффициент считается по модельному времени и часовому поясу.
  - обновлены проверки, compose, документация и статус issue 02.
- Проверка:
  - make generator-test.
  - два чистых ClickHouse-прогона с GEN_STATE_RESET=true дали одинаковые контрольные числа.
2026-06-14 17:23:12 +03:00
ddadmin 31a71f93ea docs(generator): зафиксирован контракт модельного времени
- Зачем:
  - нужно закрепить принятое человеком HITL-решение до кодовых задач 02-06.
- Что:
  - добавлен рабочий контракт настроек, хода часов, state, манифеста и ClickHouse-проверки.
  - выбран один живой ход часов через фиксированный модельный шаг без отдельной матрицы драйверов.
  - уточнена граница стартовой истории как [T0, T_end) и закрыт чек-лист issue 01.
- Проверка:
  - git diff --cached --check.
2026-06-14 16:30:15 +03:00
ddadmin 79c2c2657c docs(generator): уточнены задачи по модельному времени
- Зачем:
  - ревью выявило слабые места в критериях приёмки модельного времени.
- Что:
  - уточнены правила повторяемости, чистого прогона и review gate.
  - добавлены критерии для однородности визита через восстановление и T_end.
  - обновлён handoff с важными рисками для следующего агента.
- Проверка:
  - git diff --check.
2026-06-14 16:12:46 +03:00
ddadmin 796c3f26a9 docs(generator): добавлены задачи по модельному времени
- Зачем:
  - нужен рабочий план для реализации модельного времени и стартовой истории.
- Что:
  - добавлен parent PRD с инвариантами, зависимостями и review gate.
  - добавлены шесть локальных issue для последовательной работы.
  - добавлен handoff для продолжения в новой сессии.
- Проверка:
  - git diff --check.
2026-06-14 15:59:12 +03:00
ddadminandClaude Opus 4.8 fa93aef150 docs(context): глоссарий и спеки приведены в соответствие с ADR-0006
- Зачем:
  - ADR-0006 сделал генерацию единственным источником аналитики, а статический
    сид — архивным; глоссарий и спеки это ещё не отражали.
- Что:
  - CONTEXT.md: «статический сид» переименован в «архивный статический сид»
    (короткое имя сохранено), описан как временная кладовка значений с целью
    полного вывода; «стартовая история» получила синонимы «стартовый сид» и
    «новый сид»; раздел «Слои данных» отмечает переход аналитики на генерацию.
  - мат-спека: разделы «Персистентность через рестарты» и «Воспроизводимость»
    помечены как переописанные в спеке модельного времени (ссылкой, без повтора).
  - спека модельного времени: синоним «стартовый сид» добавлен в определение и
    в заметку о влиянии на документацию.
- Проверка:
  - git diff: термины и перекрёстные ссылки читаются непротиворечиво; ADR не
    правились (статус «архивный» не переносится в документы до ADR-0006).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 15:31:11 +03:00
ddadminandClaude Opus 4.8 18ac8279cd docs(handoff): зафиксирован handoff по ADR-0006 и спеке модельного времени
- Зачем:
  - сохранить контекст сессии для продолжения работы в новой сессии.
- Что:
  - добавлен handoff: что сделано и закоммичено, контекст вне артефактов, очередь шагов, ограничения.
- Проверка:
  - чтение .scratch/handoffs/2026-06-14-adr0006-source-flip-and-model-time-spec.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 15:07:27 +03:00
ddadminandClaude Opus 4.8 7e28cf06b9 docs(agents): язык рассуждений — английский, ответы и артефакты — русский
- Зачем:
  - кириллица занимает примерно в 1,5–2 раза больше токенов; рассуждения можно вести экономнее.
- Что:
  - добавлено правило: внутренние рассуждения и промежуточные пометки — на английском.
  - русский остаётся для ответов пользователю, документов, комментариев в коде и сообщений коммитов.
- Проверка:
  - чтение AGENTS.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 15:07:27 +03:00
ddadminandClaude Opus 4.8 c4cc01e206 docs(agents): уточнены правила русского языка и понятности документов
- Зачем:
  - прежняя формулировка допускала транслитерации и не требовала краткости и понятности самих документов.
- Что:
  - «устоявшийся английский» сужен до имён технологий, инструментов и кода.
  - добавлено правило: документы и объяснения — короткими фразами, простыми словами, понятность важнее буквальной точности.
- Проверка:
  - чтение AGENTS.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:52:09 +03:00
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
ddadminandClaude Opus 4.8 899a3f07a1 docs(research): зафиксировано внешнее ревью петли субагентов
- Зачем:
  - закрыть отложенный заход эксперимента: внешнее ревью результата
    автономной петли моделью другой родословной (дизайн-линия, не Кодекс).
- Что:
  - добавлена секция об итогах ревью: прогноз по находке A не оправдался,
    петля её поймала (try→fresh + регрессионный тест в коммите 640050e).
  - зафиксировано, что внешний взгляд добавил сквозные находки (расхождение
    живого/восстановленного путей, форма распределения длины визита).
  - уточнена гипотеза о пользе reviewer-а другой родословной.
- Проверка:
  - git show --stat HEAD; чтение docs/research/2026-06-11-subagent-coordinator-experiment.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 13:17:06 +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
ddadmin d55f183fc9 docs(course): добавлен урок по мониторингу стенда
- Зачем:
  - нужен завершённый урок 5, который объясняет мониторинг стенда без предположения, что менти уже знаком с Grafana.
- Что:
  - добавлен урок про Prometheus targets, Grafana dashboards, exporters и alert rules.
  - описан управляемый сбой через остановку airflow-scheduler и восстановление стенда.
  - обновлены навигация курса, план урока и названия панелей мониторинга в operations runbook.
- Проверка:
  - git diff --cached --check.
  - сверка названий dashboard/panel/alert rules с provisioning-файлами Grafana.
2026-06-05 20:20:42 +03:00
ddadmin 707da9f80e feat(airflow): добавлен гейт целостности DDS для урока 4
- Зачем:
  - урок 4 должен показывать не только измерение сирот в DDS, но и остановку Airflow DAG при нарушении связи dds.event -> dds.click.
- Что:
  - добавлен assert_dds_integrity в etl_pipeline и документация управляемого красного сценария.
  - вынесены общие helper'ы для SQL-split и boolean-параметров Airflow.
  - добавлен урок 4 и обновлены навигация курса, план обучения и operations notes.
- Проверка:
  - python3 -m py_compile airflow/dags/etl_pipeline_dag.py airflow/dags/ddl_init_dag.py airflow/dags/kafka_load_dag.py airflow/dags/utils/airflow_params.py airflow/dags/utils/sql_helpers.py.
  - docker compose exec -T airflow-webserver airflow dags test etl_pipeline 2026-06-05T18:00:00 -c '{"full_refresh": true}'.
2026-06-05 19:13:22 +03:00
ddadmin 4f1e58752c docs(course): добавлен урок 3 (ODS→DDS, сборка сущностей и сироты)
- Зачем:
  - собрать разрозненные кусочки ODS в цельные сущности DDS и ввести понятие
    целостности связей (сироты), пока без жёсткого гейта — он в уроке 4
- Что:
  - добавлен docs/course/lessons/03_ods_to_dds.md: сущности dds.click/dds.event,
    UNION-универсум кликов, дедуп через argMax, LEFT JOIN, понятие сироты,
    управляемая правка (вставка сироты), recap STG→ODS→DDS, заметка про DM
  - §3.1: «поток данных» в шапку sql/dds/30_ods_to_dds.sql
  - демоут DM: убран закомментированный пример материализации в
    sql/dm/40_dds_to_dm.sql, добавлены «поток данных» и заметка «VIEW сейчас,
    материализуем если затормозит» со ссылкой на docs/ARCHITECTURE.md
  - sql/ddl/dm/40_dm.sql: пояснён seed 1919 в groupArraySample, поправлен
    неверный комментарий «последние» (groupArraySample берёт случайную выборку)
  - README курса: индекс обновлён до «уроки 0–3»
- Проверка:
  - LIMIT=50 make transform: dds.click=26, dds.event=50, orphan_events=0
  - §4 на стенде: вставка события-сироты → orphan 0→1; LEFT JOIN в
    dm.v_events_enriched даёт NULL по полям клика; make transform откатывает к 0
  - /ai-text-lint (article): house style сохранён, AI-маркеры не найдены
2026-06-05 18:33:36 +03:00
ddadmin 79f7103b28 docs(course): стандарт уроков фиксирует регистр, шапку и грабли
- Зачем:
  - наработанный по урокам 0–2 мягкий регистр жил только в памяти и хендоффах;
    стандарт его не требовал — следующий урок мог уехать обратно в сжатый стиль
    и повторить уже пройденные ошибки.
- Что:
  - добавлен §2 «Регистр и голос»: расшифровка терминов на первом употреблении,
    ###-подзаголовки, разбивка «стен», человеческий тон, house style, ai-text-lint;
  - в §1 описана шапка урока (Формат / «О чём урок простыми словами»), старые
    «Статус: черновик» и «Режим: руки» помечены как не возвращать;
  - добавлен §5 «Грабли»: проверять на стенде, сверять имена с DDL, один паттерн
    на урок, спорные API ClickHouse — через MCP Context7;
  - перенумерованы разделы (качество кода → §3, самопроверка → §4) и ссылки на них.
- Проверка:
  - прочитать LESSON_STANDARD.md сверху вниз: §1–§5 идут по порядку, ссылки
    «(раздел 4)» указывают на «Самопроверку».
2026-06-05 18:00:13 +03:00
ddadmin f56166181b docs(course): смягчён регистр уроков 0–1 и убран статус «черновик»
- Зачем:
  - на уроке 2 решили писать разжёванным языком; уроки 0–1 и шапки курса
    остались в сжатом регистре, а слово «черновик»/«Режим: руки» путало менти.
- Что:
  - урок 1: расшифрованы staging, MergeTree-дедуп, Materialized View и
    виртуальные колонки; секция «Загляни внутрь» разбита на ###-подзаголовки;
    плотные абзацы разбиты на пункты; добавлен зачин «О чём урок простыми словами».
  - урок 0: добавлен зачин «О чём урок простыми словами» (лёгкая полировка).
  - шапки всех уроков: «Статус: черновик. Режим: руки/наблюдение» заменены на
    понятное «Формат: практика/наблюдение — …».
  - PRD/LEARNING_PLAN/LESSON_STANDARD: убрано слово «черновик» из статуса.
- Проверка:
  - grep -rn "черновик" docs/course/ — пусто;
  - прочитать урок 1 сверху вниз: термины раскрыты на первом употреблении.
2026-06-05 18:00:13 +03:00
ddadmin 256ac14c66 docs(course): добавлен урок 2 (STG→ODS, типизация и DQ-split)
- Зачем:
  - нужен учебный урок «руки» про типизацию слоя ODS и разделение
    чистых/битых записей; по пути убрать мусор и неочевидности в
    эталонном пути, чтобы он читался за один проход.
- Что:
  - добавлен lessons/02_stg_to_ods.md по LESSON_STANDARD (6 секций,
    режим «руки», эталон голоса — урок 1); регистр смягчён под уровень
    «обзорно» с расшифровкой терминов (click-контекст, WITH, двойной учёт).
  - 20_stg_to_ods.sql: поток данных в шапку + блок «DQ-split» (почему
    строка может попасть и в основную таблицу, и в *_errors).
  - 20_ods.sql: убран мусорный блок из 8 DROP TABLE mv_*_to_ods;
    пояснено разное партиционирование (browser — по бизнес-дате,
    click-контекст — по дате загрузки).
- Проверка:
  - make ddl && make transform — проходят чисто, counts не изменились
    (browser/location 50, device/geo 26 дедуп, *_errors 0).
  - правка §4 (toFloat64OrNull→toInt64OrNull для geo_latitude) на стенде
    даёт geo_by_click_errors 0→50 и NULL-широту с флагом bad_geo_latitude.
2026-06-05 17:08:29 +03:00
ddadmin b15ee90939 docs(course): добавлен урок 0 (вводный по Kafka, наблюдение)
- Зачем:
  - курсу нужна разминка перед уроком 1: связать словарь из обзорного
    видео по Kafka (топик, партиция, offset, группа, lag) с живым стендом.
- Что:
  - добавлен lessons/00_kafka_intro.md по LESSON_STANDARD в режиме
    наблюдения (без управляемой правки и отката), эталон голоса — урок 1.
  - честная врезка про lag: у групп ch_stg_* колонки offset/lag в Kafka UI
    пустые, прогресс чтения смотреть в ClickHouse (system.kafka_consumers).
  - README курса: в строке lessons теперь указаны уроки 0 и 1.
- Проверка:
  - факты сверены на живом кластере: 4 топика *_events по 1 партиции,
    4 группы ch_stg_* (STABLE, 1 участник); прогоном подтверждено, что
    новая группа читает топик с начала (auto.offset.reset=earliest).
2026-06-03 23:25:23 +03:00
ddadminandClaude Opus 4.8 f4d3118a42 docs(course): добавлен урок 1 и выровнена рамка под созвоны
- Зачем:
  - нужен первый урок курса по эталонному пути STG, а рамка курса описывала сопровождение как «сессию-сверку», хотя по факту это самостоятельная работа + еженедельный созвон.
- Что:
  - добавлен docs/course/lessons/01_kafka_to_clickhouse.md (Kafka → ClickHouse, слой STG) по шаблону LESSON_STANDARD.
  - в sql/ddl/stg/10_stg.sql исправлен баг kafka_ts во всех 4 MV: toInt64(DateTime64) срезал миллисекунды, kafka_ts по всему стенду был 1970-01-21; теперь _timestamp_ms присваивается напрямую (downstream на kafka_ts не опирается).
  - урок 1 §3/§4 приведены к исправленному коду; врезка про рассинхрон MV↔таблица описывает реальное поведение (молчаливый сброс лишней колонки, не ошибка).
  - «сессия/сессия-сверка» → «созвон» в PRD (датированная поправка), LESSON_STANDARD §6 (секция «Что должно получиться») и README курса; добавлена ссылка на открытый DE-роадмап.
  - в LEARNING_PLAN исправлен вердикт аудита урока 1 (баг найден прогоном), war-story про toInt64(DateTime64) припаркована в урок 2.
- Проверка:
  - прогон на стенде: make up && make ddl && LIMIT=50 make data → kafka_ts = 2026-… с миллисекундами; правка §4 (ALTER + пересоздание MV + TRUNCATE + перезаливка) и откат отработали.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 23:03:24 +03:00
ddadminandClaude Opus 4.8 d8c5e61a3a docs(course): расщеплён план уроков и зафиксирован аудит путей
- Зачем:
  - середина пайплайна перегружала один урок тремя паттернами; нужны честный такт и разведённые слои.
- Что:
  - середина расщеплена: ODS и DDS — отдельные уроки (один паттерн на урок), DM демотирован в поверхность потребления; всего 7 уроков.
  - зафиксированы финальные вердикты аудита и список правок по урокам (LEARNING_PLAN §3/§3.1), включая гейт целостности DAG.
  - в LESSON_STANDARD добавлены шаг отката «верни как было» и артефакт на сессию; в PRD обновлены скоуп и такт ~день на урок.
- Проверка:
  - вычитка docs/course/{PRD,LEARNING_PLAN,LESSON_STANDARD}.md: номера уроков, скоуп и перекрёстные ссылки сходятся.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 21:22:07 +03:00
ddadmin aecbf392d9 docs(agents): подключена doc/issue-методология Pocock и зафиксирована раскладка
- Зачем:
  - развести документацию по времени жизни: транзиентные спеки отдельно от
    долговечных решений (ADR) и доменного словаря (CONTEXT.md), вместо одного
    громоздкого spec-документа.
- Что:
  - добавлен блок Agent skills в AGENTS.md (issue tracker / triage / domain docs).
  - созданы docs/agents/{issue-tracker,triage-labels,domain}.md: локальный
    markdown-трекер в .scratch/, дефолтные triage-метки, single-context раскладка.
  - зафиксировано решение как docs/adr/0001-spec-adr-issue-layout.md.
- Проверка:
  - git show --stat HEAD; прочитать AGENTS.md и docs/adr/0001-spec-adr-issue-layout.md.
2026-06-01 23:29:50 +03:00
ddadmin dc0e6f9452 docs(course): добавлен продвинутый курс «Кликстрим на ClickHouse»
- Зачем:
  - превратить стенд в самостоятельный учебный материал (трек «со звёздочкой») для продвинутых менти.
- Что:
  - docs/course/: PRD, LEARNING_PLAN, LESSON_STANDARD и README-индекс.
  - AGENTS.md: ссылка на курс в разделе навигации.
  - CLAUDE.md: @-include AGENTS.md для контекста агента.
- Проверка:
  - открыть docs/course/README.md и пройти по ссылкам на PRD/план/стандарт.
2026-06-01 22:28:14 +03:00
ddadmin 60dfe52bb6 docs: обновлены правила оформления коммитов
- Зачем:
  - уточнен приоритет языка (русский по умолчанию)
  - добавлены критерии обязательности body
  - дополнены примеры и шаблоны
- Что:
  - изменен primary language на Russian
  - добавлены правила для AI-generated commits
  - добавлена форма глагола для русского языка (результативная)
  - перенесены шаблоны: Russian → default, English → lang:en
  - обновлены все примеры на русский язык
- Проверка:
  - git log --oneline проверяет формат
2026-02-14 11:14:06 +03:00
ddadmin 0b4c1861bb chore: add VS Code settings.json to gitignore
- Why:
  - VS Code settings are personal IDE preferences, not shared project config
- What:
  - remove !.vscode/settings.json exception from .gitignore
- Refs: AGENTS.md
2026-02-14 11:09:12 +03:00
ddadmin ec6111d260 fix(superset): stabilize bootstrap after clean reset
- make superset-init run via dedicated init service\n- tolerate missing dm views during early metadata refresh\n- add clickhouse dependency for init service\n- document clean-reset behavior and re-init flow
2026-02-11 09:48:56 +03:00
ddadmin 7819af8688 fix(superset): restore ClickHouse dialect and dataset metadata sync
- switch Superset ClickHouse URI back to clickhousedb://\n- refresh dataset metadata during init to restore filter columns\n- install runtime deps in image layer and add troubleshooting notes
2026-02-11 09:23:48 +03:00
ddadmin 9b08b924ef Merge branch 'feature/superset-dashboard' 2026-02-11 00:13:26 +03:00
ddadmin 99731850f8 fix(superset): исправлена инициализация датасетов
- Добавлен clickhouse-sqlalchemy в Dockerfile для поддержки диалекта
- Изменен URI с clickhousedb:// на clickhouse+connect://
- Убран вызов fetch_metadata() в init_superset.py (вызывал ошибку диалекта)
- Датасеты создаются без предварительного fetch_metadata

Тестирование:
- Чистый запуск: 
- Перезапуск: 
- API: 
2026-02-11 00:12:04 +03:00
ddadmin 3bed37f532 docs(docs): add 10-15 minute demo script
- Why:
  - align interview demo with recruiter requirement for 10-15 minutes
- What:
  - add timed walkthrough with code, architecture and verification points
  - include fallback steps for UI issues and final speaking script
- Check:
  - verify paths/commands against repository files and DAG ids
2026-02-10 23:57:38 +03:00
ddadmin 22f08382e5 fix(superset): align bootstrap with clickhousedb uri
- Why:
  - Superset bootstrap used outdated ClickHouse URI format and did not fail fast on init errors.
  - docs and exported dashboard metadata diverged from runtime connection settings.
- What:
  - build ClickHouse URI from env vars and use clickhousedb:// in init script.
  - refresh dataset metadata on existing datasets and surface import errors.
  - run create_dashboard during superset-init startup and align docs/exported URI references.
  - ignore node_modules in git.
- Check:
  - python3 -m py_compile superset/init_superset.py
  - manual dashboard smoke check in UI (charts render)
2026-02-10 23:51:38 +03:00
ddadmin 6533f8b32c fix(superset): fix dashboard chart rendering in Superset 4
- Why:
  - dashboard tiles failed with "Item with key 'echarts_bar' is not registered".
  - existing slice query_context stayed stale after config updates.
- What:
  - switch Top Pages and Data Quality Summary from \'echarts_bar\' to \'dist_bar\'.
  - use \'groupby\' for categorical bar charts and sync this into query_context.
  - keep dashboard export config aligned with runtime chart definitions.
- Check:
  - python3 -m py_compile superset/create_dashboard.py
  - docker compose exec -T superset python /app/superset_init/create_dashboard.py
  - DB check for slices 9/10: viz_type=form_data=query_context set to dist_bar
2026-02-10 23:49:40 +03:00
ddadmin cb3665c1be feat(superset): автоматическая инициализация с PostgreSQL метаданными
- Добавлена автоматическая инициализация Superset (подключение ClickHouse, 6 датасетов, 10 чартов, дашборд)
- Переведено хранение метаданных с SQLite на PostgreSQL (shared с Airflow)
- Добавлен superset_config.py для конфигурации PostgreSQL
- Обновлен Dockerfile.superset: postgresql-client, psycopg2-binary
- Обновлен docker-compose.yml: volume mount конфига, SUPERSET_CONFIG_PATH
- Исправлены скрипты init_superset.py и create_dashboard.py для работы с shell
- Обновлена документация в README.md: раздел Superset с инструкциями

Тестирование:
- Проверена работа после перезапуска (данные сохраняются)
- Проверен чистый запуск с нуля
- API и UI доступны
2026-02-10 21:56:47 +03:00
ddadmin 91f1a790cb fix: исправлен путь Kafka volume и обновлены скрипты Superset
- Исправлен путь Kafka volume с /tmp/kraft-combined-logs на /var/lib/kafka/data
  (решена проблема с правами доступа при старте Kafka)
- Обновлен superset/init_superset.py: улучшена обработка ошибок SQLite
- Обновлен superset/create_dashboard.py: оптимизирован импорт модулей
2026-02-10 20:48:05 +03:00
ddadmin 2e48f6065a feat: добавлен дашборд Superset для e-commerce аналитики
- Добавлен сервис superset-init в docker-compose для автоматической инициализации
- Созданы Python-скрипты для инициализации подключения ClickHouse и создания датасетов
- Создан скрипт для автоматического создания дашборда с 10 чартами
- Создан скрипт экспорта дашборда в JSON
- Добавлен экспортируемый JSON дашборда (ecommerce_analytics.zip.json)
- Обновлен Makefile с командами superset-init, superset-dashboard, superset-export
- Добавлена документация docs/SUPERSET_DASHBOARD.md

Дашборд включает:
- KPI блок (Total Events, Unique Users, Sessions, Avg/Session)
- Динамика трафика (Events by Hour, Traffic by Device)
- География (World Map)
- Маркетинг (UTM Effectiveness Table, Top Pages)
- Качество данных (DQ Summary)
- Native Filters (Date Range, Country, Device, Browser)
2026-02-10 20:48:05 +03:00
ddadmin 21fd58dc9d Merge branch 'feature/monitoring' 2026-02-09 18:53:38 +03:00
ddadmin e6c26ce353 docs(docs): add 5-minute demo cheatsheet
- Why:
  - give a student a short, repeatable interview demo script
- What:
  - add 5-minute timeline with speaking prompts
  - add SQL/CLI commands and fallback plan for UI issues
- Check:
  - review markdown content in docs/DEMO_CHEATSHEET_5MIN.md
2026-02-09 18:52:16 +03:00
ddadmin c8aca36e82 Merge branch 'feature/monitoring' 2026-02-09 10:27:59 +03:00
ddadmin f411a46aea docs(docs): add comprehensive system test plan
- Why:
  - formalize complete end-to-end verification for the demo DWH stack
  - provide fast regression checks and full validation before demo/release
- What:
  - add new TEST_PLAN.md with two execution contours: Smoke and Full
  - include checks for infra bootstrap, Airflow DAG flow, STG/ODS/DDS/DM data quality, monitoring and alert provisioning
  - add dedicated scenario proving dirty records are captured in ods.*_errors without breaking ETL
- Check:
  - aligned steps with current DAG parameters/tasks and SQL transformation flow
  - validated expected alert names against Grafana provisioning files
2026-02-09 09:56:58 +03:00
ddadmin 0e470604fe chore(scripts): add make down and clean targets
- Why:
  - intensive development needs quick cluster stop/cleanup commands
  - current Makefile had only up and pipeline/monitoring targets
- What:
  - add make target down for standard docker compose shutdown
  - add make target clean for full cleanup with volumes and orphans
  - update OPERATIONS runbook with new make commands
- Check:
  - make -n down clean
2026-02-09 09:33:54 +03:00
ddadmin e851ef9788 fix(monitoring): add recover flow for stuck monitoring stack
- Why:
  - during intensive development monitoring can get stuck (No data, out of bounds)
  - regular reload is not always enough to recover Prometheus + StatsD pipeline
- What:
  - add make target recover-monitoring for hard recovery path
  - recreate prometheus and statsd-exporter, restart airflow scheduler/webserver
  - keep Grafana provisioning reload and target checks in one command
  - document when to use recover-monitoring in OPERATIONS runbook
- Check:
  - run make recover-monitoring
  - verify Prometheus targets for airflow/clickhouse/kafka are up
2026-02-09 09:28:13 +03:00
ddadmin df173c00f7 fix(monitoring): revert incorrect clickhouse dashboard query edits 2026-02-08 23:19:54 +03:00
ddadmin 39df4f2469 fix(monitoring): add missing ClickHouse Prometheus port and fix dashboard queries
- Add port 9126 mapping for ClickHouse Prometheus metrics endpoint
  (was configured in prometheus_ch.xml but not exposed in docker-compose.yml)

- Fix CPU Usage panel: use delta() instead of rate() for gauge metric
  ClickHouseProfileEvents_OSCPUVirtualTimeMicroseconds is a gauge, not counter

- Add explicit datasource blocks to dashboard queries for consistency

ClickHouse ProfileEvents metrics correctly use rate() — they are counters.
Warning about missing _total suffix is expected (ClickHouse naming convention).
2026-02-08 23:00:32 +03:00
ddadmin a310bc6c39 fix(monitoring): align airflow statsd mapping and reload flow
- Why:
  - Airflow task metrics were mapped to non-emitted StatsD keys
  - reload-monitoring did not restart statsd-exporter after mapping changes
- What:
  - update StatsD mapping for Airflow 2.10.5 metric names
  - remove problematic catch-all mapping that produced inconsistent series
  - restart statsd-exporter in reload-monitoring flow
  - sync operations runbook and airflow monitoring plan with actual metrics
- Check:
  - make reload-monitoring
  - Prometheus targets: airflow/clickhouse/kafka are UP
  - trigger ddl_init and verify airflow_task_duration_seconds_count
  - verify airflow_task_success_total and airflow_task_failures_total in Prometheus
2026-02-08 22:51:09 +03:00
ddadmin 8a6306954e fix(monitoring): use delta() instead of rate() for CPU gauge metric
Fix Grafana warning about using rate() on gauge metric:
- ClickHouseProfileEvents_OSCPUVirtualTimeMicroseconds is a gauge, not counter
- rate() should only be used with counters; using delta() instead
- Add explicit datasource block for consistency

API verified via Context7:
- /prometheus/docs: rate() should never be used on gauges
2026-02-08 22:48:36 +03:00
ddadmin 68862a47c1 docs(repo-map): add monitoring configs and plans
Add missing entries for monitoring infrastructure:
- prometheus.yml, statsd_mapping.yml configs
- ClickHouse user configs (default_user.xml, prometheus_ch.xml)
- Grafana alerting rules for Kafka and Airflow
- Grafana dashboards for all services
- Monitoring plans (airflow, kafka)

This completes the documentation for the monitoring stack added
in the previous commits.
2026-02-08 22:33:01 +03:00
ddadmin 4917a9a6ad feat(monitoring): add Airflow monitoring via statsd-exporter
- Add statsd-exporter service to docker-compose.yml (prom/statsd-exporter:v0.27.1)
- Add StatsD env vars to airflow-default-env for metrics export
- Add airflow job to prometheus.yml scrape configs
- Add Airflow Overview dashboard (Grafana provisioning)
- Add Airflow alert rules: scheduler down, queue backlog, failures, parse time
- Add configs/statsd_mapping.yml for StatsD → Prometheus conversion
- Use Prometheus naming convention (_total for counters, _seconds for timers)
- Add monitoring plan at plans/monitoring_airflow_plan.md
- Update OPERATIONS.md and Makefile for airflow monitoring

Tested: all 3 jobs (airflow, clickhouse, kafka) showing UP in Prometheus,
metrics flowing (dagbag_size=3, executor slots, heartbeats with _total suffix),
all 4 alert rules loaded in Grafana
2026-02-08 22:27:32 +03:00
ddadmin 8e31b06241 fix(monitoring): correct Kafka metrics and alert rules
- Why:
  - dashboard showed offset as throughput and produced misleading values
  - kafka-exporter metric/label naming was inconsistent across alerts/docs
  - consumer-group-missing alert was noisy for demo runs
- What:
  - switch throughput panel to rate(kafka_topic_partition_current_offset[5m]) aggregated by topic and exclude __* topics
  - align lag metric/labels to kafka_consumergroup_lag + consumergroup
  - remove Kafka Consumer Group Missing alert from provisioning
  - pin kafka-exporter image to v1.9.0 and update OPERATIONS.md checks
- Check:
  - airflow dags list-import-errors -> No data found
  - Prometheus targets: clickhouse up, kafka up
  - PromQL kafka_consumergroup_lag returns series
  - Grafana dashboards provisioning reload returns success
2026-02-08 21:52:21 +03:00
ddadmin afdfc98eef fix(infra): harden grafana permissions and document recovery
- Why:
  - students hit permission denied after pull and grafana restart-loop with readonly db
- What:
  - run grafana as default non-root user
  - mount provisioning directory as read-only
  - add troubleshooting for git permission issues and grafana volume reset
  - normalize file modes for data jsonl and docs/DE-task.md to 100644
- Check:
  - docker compose config
  - docker compose up -d grafana
  - curl -u admin:admin http://localhost:3000/api/health
2026-02-08 21:38:23 +03:00
ddadmin ae593fd08c feat(monitoring): add Kafka monitoring via kafka-exporter
- Add kafka-exporter service to docker-compose.yml
- Add kafka job to prometheus.yml scrape configs
- Add Kafka Overview dashboard (Grafana provisioning)
- Add Kafka alert rules (broker down, consumer lag, etc.)
- Add make reload-monitoring command for easy updates
- Update OPERATIONS.md with TL;DR and troubleshooting

API verified via Context7:
- /danielqsj/kafka_exporter for exporter config
- /prometheus/docs for scrape_configs format
2026-02-08 21:25:31 +03:00
ddadmin 41c867d68d docs(operations): add post-pull monitoring refresh runbook
- Why:
  - student needs a simple way to apply Grafana/monitoring config updates after git pull
- What:
  - add TL;DR block with minimal commands in monitoring section
  - add detailed post-pull runbook for datasource/dashboard/alerting reload
  - include clickhouse restart note for prometheus_ch.xml changes
- Check:
  - reviewed commands and paths in docs/OPERATIONS.md
2026-02-08 20:53:49 +03:00
ddadmin 5270273d8a feat(monitoring): add Grafana alert rules and fix datasource binding
- Why:
  - dashboard panels could resolve to stale datasource uid and show No data
  - monitoring required proactive alerts for ClickHouse health signals
- What:
  - pin dashboard panels to prometheus_uid and remove datasource templating variable
  - fix PromQL metrics for CPU, inserted rows, and parts panels
  - add provisioning alert rules for failed queries, memory resident, and active parts
  - pin Prometheus datasource uid and update monitoring documentation
- Check:
  - POST /api/admin/provisioning/datasources/reload
  - POST /api/admin/provisioning/dashboards/reload
  - POST /api/admin/provisioning/alerting/reload
  - GET /api/v1/provisioning/alert-rules
2026-02-08 20:49:31 +03:00
ddadmin 140b711233 docs(docs): clarify multiline commit body usage
- Why:
  - commit messages with literal \n are hard to read in UI
- What:
  - add explicit rule for multiline body formatting in CLI
  - add correct examples with git commit -m and -F heredoc
- Check:
  - reviewed new section in docs/COMMIT_RULES.md
2026-02-08 20:49:18 +03:00
ddadmin fdeb48fdb2 feat(monitoring): add Grafana dashboard for ClickHouse
- Add Prometheus datasource provisioning config
- Add Grafana dashboard provider configuration
- Add ClickHouse Overview dashboard (JSON)
- Update README.md with monitoring section and updated stack badge
- Update docs/OPERATIONS.md with monitoring runbook

Dashboard includes:
- System Health: CPU, Memory Resident, Memory Code
- Query Performance: queries/sec, active queries, failed queries
- MergeTree Storage: parts count, merge rate

Verified via Context7: ClickHouse Prometheus metrics use ClickHouseAsyncMetrics_*,
ClickHouseMetrics_*, ClickHouseProfileEvents_* prefixes in v25.1.

Access:
- Grafana: http://localhost:3000 (admin/admin)
- Prometheus: http://localhost:9090
2026-02-08 20:29:43 +03:00