- Зачем:
- сохранить выводы сессии проектирования, пока свежие; без записи они теряются при компактизации и в новой сессии.
- Что:
- добавлен handoff с диагностикой двух «пожаров» — контекста координатора и токенов — по логам прогона Codex.
- зафиксированы prior art (obra:superpowers), два принятых правила, кандидаты-фиксы и открытые вопросы.
- Проверка:
- открыть .scratch/handoffs/2026-06-14-coordinator-loop-context-economy.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Зачем:
- чистый стенд должен строить аналитику из генерации, а не из архивного 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 пройден без блокирующих находок.
- Зачем:
- стенду нужна повторяемая история с живым продолжением от модельной границы без дублей и разрыва визитов.
- Что:
- добавлен 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.
- Зачем:
- рестарт генератора должен продолжать поток от модельной точки без дублей и смешивания state разных настроек.
- Что:
- state v2 хранит модельную и настенную метки, скорость, timezone, T0 и seed.
- live-восстановление считает модельную точку по настенной дельте и проверяет совместимость config.
- добавлен путь восстановления от T_end и тесты короткого и долгого простоя.
- Проверка:
- make generator-test.
- ClickHouse-сценарии короткого и долгого восстановления state.
- reviewer gate issue 04 пройден после исправления совместимости state.
- Зачем:
- ускоренный стенд должен проходить больше модельного времени и давать соответствующий событийный бюджет.
- Что:
- расчёт интенсивности переведён на модельную длительность тика.
- добавлена устойчивая выборка бюджета при больших λ.
- усилены тесты ×K, дневного коэффициента и независимости от настенного часа.
- Проверка:
- make generator-test.
- review gate после issue 03 пройден после исправления underflow Poisson.
- Зачем:
- генератор должен писать события от модельной точки T0 и проверяться повторяемо в ClickHouse.
- Что:
- добавлены настройки модельного времени и передача модельной точки в live-тик.
- дневной коэффициент считается по модельному времени и часовому поясу.
- обновлены проверки, compose, документация и статус issue 02.
- Проверка:
- make generator-test.
- два чистых ClickHouse-прогона с GEN_STATE_RESET=true дали одинаковые контрольные числа.
- Зачем:
- нужно закрепить принятое человеком HITL-решение до кодовых задач 02-06.
- Что:
- добавлен рабочий контракт настроек, хода часов, state, манифеста и ClickHouse-проверки.
- выбран один живой ход часов через фиксированный модельный шаг без отдельной матрицы драйверов.
- уточнена граница стартовой истории как [T0, T_end) и закрыт чек-лист issue 01.
- Проверка:
- git diff --cached --check.
- Зачем:
- ревью выявило слабые места в критериях приёмки модельного времени.
- Что:
- уточнены правила повторяемости, чистого прогона и review gate.
- добавлены критерии для однородности визита через восстановление и T_end.
- обновлён handoff с важными рисками для следующего агента.
- Проверка:
- git diff --check.
- Зачем:
- нужен рабочий план для реализации модельного времени и стартовой истории.
- Что:
- добавлен parent PRD с инвариантами, зависимостями и review gate.
- добавлены шесть локальных issue для последовательной работы.
- добавлен handoff для продолжения в новой сессии.
- Проверка:
- git diff --check.
- Зачем:
- ADR-0006 сделал генерацию единственным источником аналитики, а статический
сид — архивным; глоссарий и спеки это ещё не отражали.
- Что:
- CONTEXT.md: «статический сид» переименован в «архивный статический сид»
(короткое имя сохранено), описан как временная кладовка значений с целью
полного вывода; «стартовая история» получила синонимы «стартовый сид» и
«новый сид»; раздел «Слои данных» отмечает переход аналитики на генерацию.
- мат-спека: разделы «Персистентность через рестарты» и «Воспроизводимость»
помечены как переописанные в спеке модельного времени (ссылкой, без повтора).
- спека модельного времени: синоним «стартовый сид» добавлен в определение и
в заметку о влиянии на документацию.
- Проверка:
- git diff: термины и перекрёстные ссылки читаются непротиворечиво; ADR не
правились (статус «архивный» не переносится в документы до ADR-0006).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Зачем:
- сохранить контекст сессии для продолжения работы в новой сессии.
- Что:
- добавлен 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>
- Зачем:
- кириллица занимает примерно в 1,5–2 раза больше токенов; рассуждения можно вести экономнее.
- Что:
- добавлено правило: внутренние рассуждения и промежуточные пометки — на английском.
- русский остаётся для ответов пользователю, документов, комментариев в коде и сообщений коммитов.
- Проверка:
- чтение AGENTS.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Зачем:
- генератор даёт здоровую пирамиду, и стенду нужен единый источник аналитики вместо вырожденного статического сида.
- Что:
- добавлен ADR-0006: генерация — единственный источник аналитики, статический сид становится архивным (кладовка значений до синтеза фактуры).
- добавлена спека модельного времени: точка отсчёта, заливка прошлого, стартовая история, сохранение состояния, воспроизводимость и проверка в два шага.
- в ADR-0004 и ADR-0005 добавлены указатели вперёд на ADR-0006 и спеку.
- Проверка:
- чтение документов; перекрёстные ссылки между ADR-0004/0005/0006 и спекой согласованы.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Зачем:
- закрыть отложенный заход эксперимента: внешнее ревью результата
автономной петли моделью другой родословной (дизайн-линия, не Кодекс).
- Что:
- добавлена секция об итогах ревью: прогноз по находке 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>
- Зачем:
- генератор не влит и неочевидно почему; при возврате к нему легко
переоткрывать заново вывод, что click_id на событие ломает семантику визита.
- Что:
- добавлен KNOWN_ISSUES.md: модель интенсивности ок, модель сущностей неверна,
план перехода на иерархию пользователь -> сессия -> событие.
- в шапку README.md добавлено предупреждение со ссылкой на KNOWN_ISSUES.md.
- Проверка:
- прочитать generator/KNOWN_ISSUES.md и сверить с generate_batch() в generator.py.
- Зачем:
- нужно зафиксировать архитектуру перехода от 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, параллельность)
- Зачем:
- нужна визуализация метрик 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)
- Зачем:
- упростить и сделать безопаснее сериализацию состояния генератора
- повысить устойчивость старта при временной недоступности Kafka
- Что:
- заменена сериализация rng state на JSON-safe формат без pickle/base64
- добавлено восстановление tuple-структуры rng state после json
- добавлен общий retry с exponential backoff для ensure_topics
- обновлена документация по continuity и ограничениям после рестарта
- расширены тесты state-сценариев и retry-логики
- Проверка:
- make generator-test
- 50 passed
- Зачем:
- генератор должен продолжать работу с места остановки после падения/рестарта
- нужно сохранять 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
- Изолированы ошибки history-канала: best-effort с логированием, не валят тик
- Добавлено явное создание топика generator_batch_history при старте
- Добавлена защита от пустого словаря (ValueError при загрузке)
- Обновлена документация о структуре тестов
- Исправлены тесты на пустой словарь
Ревью: изоляция ошибок history, явное создание топика, защита от пустых данных
- Удалён класс InMemoryBatchHistory и вся fallback-логика
- Упрощён KafkaBatchHistory: убраны _initialized, get_stats(), обработка ошибок
- Обновлена документация (generator/README.md, docs/OPERATIONS.md)
- Упрощены тесты, удалены тесты для удалённого функционала
- Код стал честнее: без Kafka генератор падает при старте
Ревьюер: Prometheus даёт достаточно visibility, fallback избыточен
- Зачем:
- ревью 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
- Зачем:
- были только 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 тестов пройдено
- Зачем:
- нужен постоянный поток данных для демонстрации работы стека
- текущий 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 сообщения
- Зачем:
- зафиксировать решение об observability генератора на уровне MVP-плана
- Что:
- добавлены требования по /metrics, scrape_config и target generator:9109
- добавлен env-параметр GEN_METRICS_PORT
- обновлены шаг внедрения и критерии успеха
- Проверка:
- проверен diff только для plans/generator_demo_stream_plan.md
- Зачем:
- убрать рассинхрон между кратким ТЗ, архитектурой и планом генератора
- Что:
- сокращен 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 по измененным файлам
- в коммит включены только мои документационные изменения
- Зачем:
- зафиксировать реалистичный MVP без переусложнения
- Что:
- оставлен один режим steady для автономного генератора
- добавлена минимальная статистическая модель потока на базе Poisson
- уточнены минимальные метрики, история batch и короткий roadmap внедрения
- Проверка:
- проверен diff и итоговое содержимое plans/generator_demo_stream_plan.md
- Зачем:
- фича готова: продвинутый курс (уроки 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 — два родителя.
- Зачем:
- следующей сессии нужна точка опоры: что сделано, какой канон у слоёв и какие
хвосты остались вне скоупа.
- Что:
- добавлен .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 актуальны.
- Зачем:
- при переработке README выяснилось, что профильные доки местами
отстали от кода; находки нужно сохранить как отдельную задачу, чтобы
не потерять и чинить отдельным проходом.
- Что:
- добавлен .scratch/docs-accuracy-audit/findings.md со сверенными с
кодом расхождениями ARCHITECTURE, OPERATIONS, REPO_MAP,
SUPERSET_DASHBOARD (с привязкой к файлам и строкам).
- находки разнесены по серьёзности и снабжены порядком починки.
- Проверка:
- открыть .scratch/docs-accuracy-audit/findings.md; сверить 🔴-пункты
с указанными строками кода.
- Зачем:
- стенд теперь учебный (для менти и для экспериментов), рекрутерская
рамка 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 и
рабочие ссылки на профильные доки.
- Зачем:
- следующая сессия продолжает работу над документацией с фокусом на
корневой README; нужен контекст (модель курса, голос, подходы), а не
чек-лист задач.
- Что:
- добавлен .scratch/handoffs/2026-06-06-root-readme-polish.md: модель
курса, линза mentee-first, рабочие подходы, состояние git и рабочего
дерева, направление по корневому README (без предписаний).
- Проверка:
- чистый .md, прогон стенда не нужен.
- Зачем:
- прежний 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 сохранён).
- Зачем:
- нужно снять двусмысленность между 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.
- Зачем:
- финализация подготовки уроков: пройти обязательный 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.
- Зачем:
- сквозной ревью курса нашёл расхождения учебного текста с реальным выводом
стенда и один баг в операторских доках — менти увидел бы не то, что в уроке.
- Что:
- урок 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.
- Зачем:
- все 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 нет
- Зачем:
- урок 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.
- Зачем:
- после замены DQ-чарта на row-lineage в списке «на какие вопросы отвечает
BI» остался повисший пункт «есть ли видимые проблемы качества данных» —
чарта, который на него отвечал, больше нет.
- Что:
- пункт переформулирован под актуальный чарт Rows by Layer
(«доходят ли строки до витрины без потерь по слоям конвейера»).
- Проверка:
- сквозная вычитка урока 6: состав чартов, имена и числа согласованы.
- Зачем:
- все события стенда укладываются в ~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, консоль чистая.
- Зачем:
- после смены чарта на 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 пуст.
- визуальная вычитка изменённых разделов.
- Зачем:
- чарт «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, консоль без ошибок.
- Зачем:
- нужно убрать дублирующий 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.
- Зачем:
- Codex силён в реализации, но визуальную приёмку дашборда не вытянет —
нужно явно оставить screenshot sign-off человеку/vision-агенту.
- Что:
- в handoff добавлен блок «Если задачу берёт Codex»: не визуальные само-проверки
его, визуальный sign-off — отдельно.
- Проверка:
- .scratch/handoffs/2026-06-06-...md содержит блок и не закрывает done по визуалу.
- Зачем:
- дашборд-эталон показывал две одинаковые KPI-плитки; нужен честный состав метрик
на полных данных, зафиксированный до реализации.
- Что:
- docs/specs/2026-06-06-...: KPI Events/Users/Avg per Visit/Conversion, Top Pages → Funnel, триаж чартов.
- .scratch/handoffs/2026-06-06-...: handoff для реализации в новой сессии.
- Проверка:
- числа спеки сверены с прямым запросом в ClickHouse на полном датасете.
- Зачем:
- зафиксировать доменный язык, чтобы метрики дашборда и урок 6 опирались на единые термины.
- Что:
- добавлен CONTEXT.md: пользователь/визит-сессия/событие, иерархия, почему на демо Users == Sessions.
- Проверка:
- термины сверены с sql/ddl/dds/30_dds.sql и sql/ddl/dm/40_dm.sql.
- Зачем:
- артефакты браузерной автоматизации не должны попадать в индекс.
- Что:
- добавлены .playwright-cli и .playwright-mcp в .gitignore.
- Проверка:
- git status не показывает .playwright-cli/ после прогона playwright-cli.
- Зачем:
- дашборд рендерился одной колонкой во всю ширину, а 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.
- Зачем:
- 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.
- Зачем:
- перечитка урока 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 (вывод не изменился —
на чистом срезе несовпадений нет)
- Зачем:
- нужен завершённый урок 5, который объясняет мониторинг стенда без предположения, что менти уже знаком с Grafana.
- Что:
- добавлен урок про Prometheus targets, Grafana dashboards, exporters и alert rules.
- описан управляемый сбой через остановку airflow-scheduler и восстановление стенда.
- обновлены навигация курса, план урока и названия панелей мониторинга в operations runbook.
- Проверка:
- git diff --cached --check.
- сверка названий dashboard/panel/alert rules с provisioning-файлами Grafana.
- Зачем:
- урок 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}'.
- Зачем:
- собрать разрозненные кусочки 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-маркеры не найдены
- Зачем:
- наработанный по урокам 0–2 мягкий регистр жил только в памяти и хендоффах;
стандарт его не требовал — следующий урок мог уехать обратно в сжатый стиль
и повторить уже пройденные ошибки.
- Что:
- добавлен §2 «Регистр и голос»: расшифровка терминов на первом употреблении,
###-подзаголовки, разбивка «стен», человеческий тон, house style, ai-text-lint;
- в §1 описана шапка урока (Формат / «О чём урок простыми словами»), старые
«Статус: черновик» и «Режим: руки» помечены как не возвращать;
- добавлен §5 «Грабли»: проверять на стенде, сверять имена с DDL, один паттерн
на урок, спорные API ClickHouse — через MCP Context7;
- перенумерованы разделы (качество кода → §3, самопроверка → §4) и ссылки на них.
- Проверка:
- прочитать LESSON_STANDARD.md сверху вниз: §1–§5 идут по порядку, ссылки
«(раздел 4)» указывают на «Самопроверку».
- Зачем:
- на уроке 2 решили писать разжёванным языком; уроки 0–1 и шапки курса
остались в сжатом регистре, а слово «черновик»/«Режим: руки» путало менти.
- Что:
- урок 1: расшифрованы staging, MergeTree-дедуп, Materialized View и
виртуальные колонки; секция «Загляни внутрь» разбита на ###-подзаголовки;
плотные абзацы разбиты на пункты; добавлен зачин «О чём урок простыми словами».
- урок 0: добавлен зачин «О чём урок простыми словами» (лёгкая полировка).
- шапки всех уроков: «Статус: черновик. Режим: руки/наблюдение» заменены на
понятное «Формат: практика/наблюдение — …».
- PRD/LEARNING_PLAN/LESSON_STANDARD: убрано слово «черновик» из статуса.
- Проверка:
- grep -rn "черновик" docs/course/ — пусто;
- прочитать урок 1 сверху вниз: термины раскрыты на первом употреблении.
- Зачем:
- нужен учебный урок «руки» про типизацию слоя 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.
- Зачем:
- курсу нужна разминка перед уроком 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).
- Зачем:
- нужен первый урок курса по эталонному пути 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>
- Зачем:
- середина пайплайна перегружала один урок тремя паттернами; нужны честный такт и разведённые слои.
- Что:
- середина расщеплена: 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>
- Зачем:
- развести документацию по времени жизни: транзиентные спеки отдельно от
долговечных решений (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.
- Зачем:
- превратить стенд в самостоятельный учебный материал (трек «со звёздочкой») для продвинутых менти.
- Что:
- docs/course/: PRD, LEARNING_PLAN, LESSON_STANDARD и README-индекс.
- AGENTS.md: ссылка на курс в разделе навигации.
- CLAUDE.md: @-include AGENTS.md для контекста агента.
- Проверка:
- открыть docs/course/README.md и пройти по ссылкам на PRD/план/стандарт.
- Зачем:
- уточнен приоритет языка (русский по умолчанию)
- добавлены критерии обязательности body
- дополнены примеры и шаблоны
- Что:
- изменен primary language на Russian
- добавлены правила для AI-generated commits
- добавлена форма глагола для русского языка (результативная)
- перенесены шаблоны: Russian → default, English → lang:en
- обновлены все примеры на русский язык
- Проверка:
- git log --oneline проверяет формат
- Why:
- VS Code settings are personal IDE preferences, not shared project config
- What:
- remove !.vscode/settings.json exception from .gitignore
- Refs: AGENTS.md
- 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
- 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
- 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
- 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)
- 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
- Добавлена автоматическая инициализация 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 доступны
- Исправлен путь Kafka volume с /tmp/kraft-combined-logs на /var/lib/kafka/data
(решена проблема с правами доступа при старте Kafka)
- Обновлен superset/init_superset.py: улучшена обработка ошибок SQLite
- Обновлен superset/create_dashboard.py: оптимизирован импорт модулей
- 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
- 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
- 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
- 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
- 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).
- 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
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
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.
- 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
- 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
- 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
- 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
- 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
- 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
- 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