Зачем: тикет #23 — каждое цитируемое число курса сверено с живым
стендом; до этого в уроках стояли заглушки.
Что:
- уроки 00–04: 18 маркеров заполнены числами свежего импорта
(280 437 событий, нули в таблицах ошибок, счётчики ODS/DDS);
- лаба 07: таблица manifest после дня 4 (374 092 / 34 801 / 5 388),
переходящие визиты по стыкам (35/22/26), числа после дня 5;
- лаба 08: каноническая граница трёх дней, пример замера свежести
(лаг 3:45 модельного времени до догона, ETL ~29 с) и вернувшегося
пользователя; две живые поправки разбора времени: убран
принудительный UTC в разборе STG и суффикс +00:00 в сравнении
границы (ловились только на живом стенде).
Проверка: детерминизм подтверждён двумя независимыми циклами
сброс→импорт→инкремент (числа manifest и checksum_sha256 дней 4 и 5
совпали бит в бит); chain-check зелёный; сценарий лабы 08 прогнан
вживую, включая стоп/продолжение и красный full_refresh=false из
урока 4; grep «сверить-на-стенде» пуст; ссылки и якоря целы;
make test (219+31) и make lint зелёные; /ai-text-lint по лабам — без
существенных находок.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Зачем: после редизайна пути менти курс ссылался на старый путь
generated-history-analytics/backfill и не проходился по новому стенду.
Что: в README курса — единый блок подготовки и канонического сброса
(make clean -> make up + ddl_init/world_init -> make superset-init),
таблица уроков дополнена лабами 07–08 («в работе»); LESSON_STANDARD и
уроки 0–6 ссылаются на канонический блок; урок 1 переведён на дозаливку
через world_next_day (кнопкой-анонсом, цена в минутах названа); урок 4 —
лесенка DAG-ов; урок 5 — словарь «база import / живой поток»; урок 6
обязателен; цифры старого мира помечены маркером «сверить-на-стенде».
Проверка: grep по generated-history-analytics/backfill в docs/course/
пуст; правки только в docs/course/; git diff --check чистый.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Зачем:
- учебный путь должен идти через генерацию и штатный пайплайн, а не через архивный сид.
- Что:
- обновлены уроки 00-06 и стандарт урока под startup-history/backfill.
- объяснено, что data/*.jsonl остаются кладовкой значений генератора.
- тест-план переведён на новый штатный запуск и HITL-приёмку.
- Проверка:
- rg -n \"make clean/up/ddl/data/transform|make data|kafka_load|LIMIT=|2022-11-28|26 из 50\" docs/course docs/TEST_PLAN.md.
- git diff --cached --check.
- Зачем:
- сквозной ревью курса нашёл расхождения учебного текста с реальным выводом
стенда и один баг в операторских доках — менти увидел бы не то, что в уроке.
- Что:
- урок 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.
- Зачем:
- перечитка урока 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 (вывод не изменился —
на чистом срезе несовпадений нет)
- Зачем:
- собрать разрозненные кусочки 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-маркеры не найдены