# Редизайн пути менти: мир из артефакта и две ветки роста Статус: принято, в работе (ветка `feature/mentee-path`). Источник: ручной HITL-прогон пути менти 2026-07-19 — находки F1–F9 (рабочая копия — `.scratch/hitl-findings.md`; постоянный след — история git, срез `0e312b3`). Решения приняты в обсуждении с пользователем 2026-07-19. ## Проблема Сегодняшний первый шаг менти — `backfill`: генерация истории с нуля. Это медленно (день модельной истории — минуты и десятки минут CPU), а результат беден (6 часов плоского профиля `ci`). Вокруг — ворох трения: - пульт `generator_control` подсовывает `backfill` дефолтом и носит имя, непонятное осваивающему стенд; - два профиля (`ci`/`daily-wave`) путают: менти достаётся плоский тестовый; - `next-day` спрятан в общем пульте и не годится для расписания: каждый прогон перечитывает всю историю Kafka заново — стоимость растёт квадратично по дням, память — линейно (риск OOM); - готового артефакта в репозитории нет: механизм `import` есть, а импортировать нечего. ## Цели - Менти получает богатый мир за секунды-минуты, а не генерирует его. - Путь менти проходится в Airflow UI пустыми формами, без справочника. - У всех менти одинаковый мир: числа в лабах воспроизводимы число-в-число. - Мир можно растить двумя осознанными способами: пакетно по дням и живым потоком. - Плановый `next-day` перестаёт дорожать с возрастом мира. ## Целевая модель **Основной режим менти — `import` эталонного мира.** От восстановленного состояния расходятся две ветки — это три режима менти (термины — в `CONTEXT.md`): - **База: `import`** — загрузить эталонный мир из артефакта в git. - **Ветка A: `next-day`** — пакетно добавить следующий модельный день. - **Ветка B: `continue`** — живой поток от той же границы (скорость ×60). `backfill` уходит мейнтейнеру: это инструмент сборки эталонного мира, не первый шаг менти (аналогия из соседнего курса Airflow: по умолчанию загружают готовый первый месяц, а не собирают его генератором). ### Путь менти (UX) 1. `make up` — поднять стенд (единственная команда терминала). 2. Airflow UI: `ddl_init` — создать схему. 3. Airflow UI: `world_init` — Trigger с пустой формой. Дефолтная операция — `import`, путь к артефакту — дефолтом на эталонный мир. DAG сам заливает Kafka, запускает ETL и сверяет витрины. 4. Superset — готовый трёхдневный мир. 5. Дальше по выбору лабы: `world_next_day` (кнопка без параметров) или `make generator-continue` (живой поток). ### Решения 1. **Эталонный мир**: 3 модельных дня на профиле `daily-wave` (суточная волна видна, есть «средний» день и сравнение день-к-дню). Собирает мейнтейнер один раз через `backfill`; хранится в git по фиксированному пути `data/startup_history/` сжатым `xz` (~13 МБ; замер 2026-07-19: `xz -9e` жмёт артефакт в 48 раз). Формат не меняется: `import` требует `raw_topics`, сжатие снимает вопрос размера. Паттерн-образец — `airflow-greenplum-solution` (сид `demo.sql.xz` в git, стрим-распаковка при загрузке). 2. **Пульт переименовывается: `generator_control` → `world_init`.** Дефолт формы — `import` (сейчас `backfill` — корень находки F3); `backfill` и `check` остаются в выпадашке, но уходят из учебных инструкций в runbook мейнтейнера. Список DAG'ов читается лесенкой: `ddl_init` → `world_init` → `world_next_day`. Цена: история прогонов старого dag_id теряется (на учебном стенде не жалко), доки и контрактный тест правятся синхронно. 3. **`world_next_day` — отдельный беспараметрный DAG**: триггернул — день добавился. `schedule` прописан, но DAG paused и `catchup=False`: процесс тяжёлый, автозапуск включается осознанно (шаг лабы), живой рост мира и так даёт ветка `continue`. 4. **Инкрементальные счётчики manifest — предусловие расписания.** Накопительное состояние счётчиков (суммы, множества uid/click_id, катящаяся контрольная сумма) переезжает в state/manifest; новый день только добавляется. Полная перечитка Kafka уходит: стоимость дня становится ~постоянной (сейчас день 2 — 638 с и растёт), риск OOM снимается. Разбор по коду — hitl-findings, F9. 5. **Один учебный профиль**: `daily-wave` (волна, ×60). `ci` (×1, плоско, 6h) — служебный для автотестов, менти не предлагается. Перед слиянием проверить, что runtime-seam-тест не завязан на скорость ×1. ## Чего здесь не делаем - **Не параллелим генерацию** — ломает детерминизм (один поток ГПСЧ, переходящие визиты); корень стоимости не в ней, а в перечитке (F9). - **Не трогаем гео-фактуру** — отдельная спека по ADR-0006. - **Не мигрируем лабы курса** (`docs/course/`) — они отстали от реальности и потребуют редизайна под три режима; отдельная работа, зафиксирована issue в трекере. - **Не чиним здесь F5** (быстрый разлогин Airflow/Superset) **и F4** (JS-ошибка Grid) — отдельные issues вне фичи. - **Не включаем расписание по умолчанию** и не занимаемся retention сверх инкрементальных счётчиков. ## Форма работ Четыре дочерних issue (GitHub, по контракту `docs/agents/issue-tracker.md`; корневой issue ссылается сюда): 1. **Эталонный мир**: сборка 3-дневного артефакта, `xz`-хранение в git, стрим-распаковка на `import`, дефолтный путь в форме. 2. **Поверхность DAG'ов**: переименование в `world_init`, дефолт `import`, вынос `world_next_day` беспараметрным DAG'ом с paused-расписанием, синхронная правка доков и контрактных тестов. 3. **Инкрементальные счётчики manifest** (без них расписание не включать). 4. **Один учебный профиль**: `daily-wave` — учебный дефолт, `ci` — служебный; проверка независимости runtime-seam-теста от ×1. Зависимости: (1) и (4) сцеплены (эталонный мир собирается на `daily-wave`); (3) блокирует включение расписания из (2), но не сам DAG. ## Проверка - Чистый стенд: путь менти из раздела UX проходится пустыми формами; от `make up` до дашборда — без документации и без терминала (кроме `make up`). - `import` эталонного мира — секунды-минуты, не десятки минут. - После `import` у любого менти совпадают manifest-числа эталонного мира (события, визиты, пользователи, контрольная сумма). - `world_next_day` на дне N по времени ~равен дню 1; `make generated-history-chain-check` зелёный на стыках. - `make test` / `make lint` зелёные; профиль `ci` продолжает обслуживать автотесты. ## Решения и отклонённые варианты - **Без артефакта, просто ускорить backfill** — отклонено: время менти и воспроизводимость (общий файл надёжнее «одинаковой генерации у всех»). - **Мир «из коробки» при `make up`** — отклонено: механизм становится невидимым, магия в учебном стенде мстит; явный `import` — учебная ценность и общее начало обеих лаб. - **Расписание включённым по умолчанию** — отклонено: эпизодический стенд, тяжёлый процесс, сюрпризы catchup. - **Три тонких DAG вместо пульта** — отклонено: плодит сущности; пульт с правильным дефолтом + один тонкий `world_next_day` достаточно. - **git-lfs / релизные ассеты для артефакта** — отклонено: после `xz` артефакт помещается в обычный git. ## Влияние на документацию - `README.md`, `docs/OPERATIONS.md`, `docs/ARCHITECTURE.md`, `docs/REPO_MAP.md` — новый путь менти и имена DAG'ов (в тех же PR, что и изменения). - `docs/runbooks/startup-history.md` — `backfill`/сборка эталонного мира переезжают сюда как процедура мейнтейнера; дополнить про размер и хранение. - `CONTEXT.md` — термины «мир (стенда)», «эталонный мир», «три режима менти» (добавлены этой же спекой). - Лабы `docs/course/` — сознательно не здесь (см. «Чего не делаем»).