Status: ready-for-agent # Глагол next-day: собрать следующий модельный день ## Parent `.scratch/generator-model-time-startup-history/PRD.md` ## Why Рамка пересмотрена 2026-07-07 (обсуждение с пользователем). Было: «удлинить готовую историю» (2 суток -> 7) — этот мотив закрыл портативный артефакт (задача 07), приоритет был низкий. Стало: **режим кормления стенда порциями**. Ценность не в длине истории, а в дискретности подачи: - **Урок.** Менти триггерит «следующий день» -> в Kafka падает батч за новый модельный день -> прогон `etl_pipeline` -> витрины и дашборды сдвинулись. Полный цикл DWH виден за один шаг; повторяемо и управляемо, в отличие от непрерывного live. - **Имитация жизни.** Тот же механизм по расписанию (`@daily` или чаще) — стенд «живёт»: мониторинги бегут, метрики копятся, нагрузка видна. - Удлинение истории остаётся как частный случай (несколько next-day подряд). ## Интерфейс Новый глагол `next-day` в существующем DAG `generator_control` (`airflow/dags/generator_control_dag.py`), не отдельный DAG: менти уже знает, где ручки генератора; pause-check `etl_pipeline` и guard чистого стенда переиспользуются. Ручной триггер — для урока, расписание — для «жизни». ## Развилка реализации — решена (пользователь, 2026-07-07) **Выбран вариант 2: генерация следующего дня от слепка `T_end`.** Обоснование. Диагноз задачи 20 показал, что генератор на стыке ничего не ломает — красный гейт был гонкой в самой проверке. Страх «швов» был страхом перед артефактом верификатора. При этом оба варианта одинаково требуют цепочку манифестов и расширение проверок, а вариант 1 сверх того требует новый режим среза в импорте («всё или ничего» сейчас). То есть вариант 2 не дороже, честнее (жизнь стенда не ограничена длиной артефакта) и переиспользует уже закалённый restore-механизм (задача 09: донор в state, громкие ошибки, детерминированная запасная ветка). Отклонено: вариант 1 (резать готовый артефакт на дневные порции) — не даёт неограниченной жизни и требует своей новой механики импорта. ## Открытые вопросы (блокируют ready-for-agent) - [x] Умеет ли текущий импорт артефакта (`startup-history-import`) подавать историю частями? **Нет, «всё или ничего»** (проверено 2026-07-07): скрипт требует чистый стенд (`import_startup_history_artifact.sh:50`, `assert_stand_clean.sh`), CLI артефакта воспроизводит все топики целиком и не имеет опций среза, а валидация жёстко связывает manifest и state (`startup_history_artifact.py`, `_validate_manifest_state`). Для варианта 1 нужен новый режим импорта: срез по модельному дню, цепочка manifest'ов вместо «manifest равен state», и ослабление guard'а чистого стенда для последующих порций (граница по манифесту вместо пустоты). Нюанс: артефакт хранит один state на конец полной истории, поэтому live-продолжение возможно только после последней порции; промежуточные дни — batch-only (для учебного сценария этого достаточно). - [x] Для варианта 2 — решение по запасной ветке рождения визита: **уже закрыто фиксом задачи 09** (проверено по коду 2026-07-07 при диагнозе задачи 20): ветка хранит донора (`generation.py:194-209`) и громко падает на неполных locations, восстановление воспроизводит её детерминированно. ## Acceptance criteria (черновые) - [ ] Глагол `next-day` в `generator_control`: батч ровно за один следующий модельный день от текущей границы манифеста. - [ ] Идемпотентность: повторный триггер того же дня — громкий отказ по манифесту, а не второй мир и не дубли. - [ ] Манифест двигает `T_end` атомарно; антисмешивание работает на **цепочке** границ (30 батчей = 30 границ), проверки (`scripts/check_generated_analytics.sh` и родня) расширены с одной границы на цепочку. - [ ] Учебный цикл целиком: после `next-day` прогон `etl_pipeline` даёт новые строки в DM-витринах; проверка повторяемая, не разовая. - [ ] Для варианта 2: визиты, пережившие границу батча, однородны по всем per-event полям (браузер, referer, utm) — тот же класс проверки, что в задаче 09. ## Blocked by - Нет. Последний блокер снят 2026-07-12: `20-flaky-runtime-seam-check.md` закрыта, гейт стыка стабилен (3 подряд зелёных прогона, красный сценарий ловится). - Исторические блокеры закрыты: `15-world-boundary-after-cross-review.md` (граница миров) и `17-trusted-checks-startup-history-superset.md` (доверенные проверки) — done. Исторический контекст: `09-seam-browser-fixture-not-preserved.md` — шов рождается при любом прохождении мира через сериализованный state (рестарт, сбой, доливка — один код восстановления); фикс 09 положил донора фактуры в state и закрыл тихие fallback'и. Прежняя редакция этой задачи называлась «Доливка стартовой истории кусочком от слепка».