docs(generator): добавлены задачи по модельному времени

- Зачем:
  - нужен рабочий план для реализации модельного времени и стартовой истории.
- Что:
  - добавлен parent PRD с инвариантами, зависимостями и review gate.
  - добавлены шесть локальных issue для последовательной работы.
  - добавлен handoff для продолжения в новой сессии.
- Проверка:
  - git diff --check.
This commit is contained in:
2026-06-14 15:59:12 +03:00
parent fa93aef150
commit 796c3f26a9
8 changed files with 380 additions and 0 deletions
@@ -0,0 +1,80 @@
# Модельное время и стартовая история генератора
Status: Draft
## Зачем
Нужно довести решение ADR-0005 и ADR-0006 до рабочего процесса: генератор живёт
по модельному времени, умеет быстро создать прошлое, сохранить слепок состояния
и продолжить поток так, чтобы результат был проверяем в ClickHouse.
Источник решений:
- `docs/specs/2026-06-14-generator-model-time-and-startup-history.md`
- `docs/adr/0005-generator-model-clock.md`
- `docs/adr/0006-generation-as-sole-analytics-source.md`
- `docs/research/2026-06-11-subagent-coordinator-experiment.md`
## Общие правила приёмки
- Каждый кодовый срез должен заканчиваться проверкой через ClickHouse, а не
только локальными тестами генератора.
- Быстрый цикл внутри задачи идёт через `/tdd`: один поведенческий тест,
минимальная реализация, зелёная проверка.
- Координатор не работает в `/goal` на всю цепочку. Один worker получает один
issue, не коммитит и не реализует следующие задачи.
- После реализации worker делает саморевью без правок. Координатор
классифицирует находки и возвращает только обязательные исправления.
- Коммиты делает координатор после своих проверок и `git status --short`.
- Ручная проверка дашбордов глазами выполняется только в конце всей цепочки.
## Сквозные инварианты
- `event_timestamp` — модельное время, а не настенные часы компьютера.
- Операционные метки сервиса, история пачек, метрики здоровья и длительность
тика остаются настенным временем, если отдельная задача не докажет обратное.
- При одинаковых `GEN_SEED`, `T0`, скорости и настройках поток повторяем.
- При ×K модельное время и событийный бюджет идут по модельной длительности
тика, а не по реальной длительности сна процесса.
- После сбоя точка возобновления считается из сохранённой связки модельного и
настенного времени, а не простым `datetime.now()`.
- Стартовая история — это события плюс слепок состояния плюс манифест, чтобы не
смешать данные от разных `GEN_SEED`, `T0` и `T_end`.
- На стыке `[T0, T_end]` и живого продолжения не должно быть дублей и дыр.
- Повторная проверка на чистом стенде должна быть воспроизводимой: либо команда
явно чистит данные, либо процесс идемпотентен.
## Задачи
1. `issues/01-time-and-startup-history-contract.md` — контракт модельного
времени и стартовой истории.
2. `issues/02-model-time-to-clickhouse.md` — минимальный поток по модельному
времени до ClickHouse.
3. `issues/03-model-speed-and-day-factor.md` — ×K и дневной коэффициент по
модельному времени.
4. `issues/04-state-v2-model-resume.md` — восстановление state v2 от модельной
точки возобновления.
5. `issues/05-startup-history-backfill-to-clickhouse.md` — промотка прошлого,
стартовая история и живое продолжение до ClickHouse.
6. `issues/06-generated-history-as-analytics-source.md` — штатный путь стенда
переводится на стартовую историю как источник аналитики.
## Контрольные точки
- После задачи 3 нужен внешний review gate по сквозному инварианту времени:
проверить, где ещё остались настенные часы, и не расходятся ли живой путь,
расчёт интенсивности и сохранение состояния.
- После задачи 5 нужен внешний review gate по распределениям и двум путям
генерации: проверить форму данных, стык истории и живого продолжения,
однородность визита до и после восстановления.
Для этих контрольных точек по возможности нужен reviewer другой родословной, а
не тот же worker: research показал, что сквозные свойства и форма распределений
хуже ловятся одной линией проверки.
## Финальная ручная приёмка
После задачи 6 человек смотрит Superset/Grafana и проверяет, что стенд живёт на
генерации: видны история, возвраты, воронка и суточное «дыхание». Если текущих
панелей не хватает для такого просмотра, создаётся отдельная задача на панель
или runbook, а не расширяется эта цепочка задним числом.
@@ -0,0 +1,39 @@
Status: ready-for-human
# Контракт модельного времени и стартовой истории
## Parent
`.scratch/generator-model-time-startup-history/PRD.md`
## What to build
Зафиксировать рабочий контракт для реализации модельного времени и стартовой
истории. Это HITL-срез: до кода нужно решить внешний интерфейс, формат
стартовой истории и правила восстановления, чтобы worker-и не угадывали
поведение через тесты.
Контракт должен остаться коротким и понятным: что задаёт `T0`, как задаётся ×K,
что такое `T_end`, как выглядит стартовая история, какие метки времени
модельные, а какие операционные.
## Acceptance criteria
- [ ] Выбраны имена и формат настроек для `T0`, скорости ×K и режима промотки
прошлого.
- [ ] Описано, как после сбоя вычисляется модельная точка возобновления при ×K:
из сохранённой модельной метки, сохранённой настенной метки и скорости.
- [ ] Описан манифест стартовой истории: минимум `GEN_SEED`, `T0`, `T_end`,
настройки генерации, версия state и контрольные числа.
- [ ] Описана граница `T_end`: где заканчивается прошлое и с какой метки
начинается живое продолжение, без дублей и дыр.
- [ ] Разделены модельные метки событий и настенные операционные метки сервиса.
- [ ] Решено, как координатор будет получать повторяемую ClickHouse-проверку:
через очистку данных или идемпотентный прогон.
- [ ] Контракт записан в durable-документ: обновление `PRD.md`, короткий
design note в `.scratch/generator-model-time-startup-history/` или уточнение
спеки. Сам issue 01 только ссылается на источник истины.
## Blocked by
None - can start immediately
@@ -0,0 +1,34 @@
Status: ready-for-agent
# Модельное время до ClickHouse
## Parent
`.scratch/generator-model-time-startup-history/PRD.md`
## What to build
Сделать минимальный живой поток, где генератор стартует от `T0`, пишет
`event_timestamp` по модельному времени и доводит события до ClickHouse
обычным путём стенда. Срез должен доказать не внутренний класс часов, а
наблюдаемое поведение: данные в ClickHouse начинаются от модельной точки и
повторяются при тех же настройках.
## Acceptance criteria
- [ ] При фиксированных `GEN_SEED` и `T0` первый короткий прогон пишет события с
модельными `event_timestamp`, начинающимися около `T0`.
- [ ] Повторный чистый прогон с теми же настройками даёт те же контрольные
числа в ClickHouse.
- [ ] Расчёт дневного коэффициента в этом срезе больше не зависит от реального
часа запуска процесса.
- [ ] Локальные тесты проверяют поведение через публичный интерфейс генератора
или сервиса, без привязки к внутреннему устройству часов.
- [ ] Есть команда или короткая инструкция для координатора: поднять стенд,
прогнать поток, выполнить SQL-проверку в ClickHouse.
- [ ] Документация запуска не утверждает, что `event_timestamp` равен
настенному времени.
## Blocked by
- `.scratch/generator-model-time-startup-history/issues/01-time-and-startup-history-contract.md`
@@ -0,0 +1,36 @@
Status: ready-for-agent
# ×K и дневной коэффициент по модельному времени
## Parent
`.scratch/generator-model-time-startup-history/PRD.md`
## What to build
Добавить ускоренный живой ход модельных часов. При ×K за один реальный тик
должна проходить большая модельная длительность, а событийный бюджет должен
считаться по этой модельной длительности. Дневной коэффициент считается по
модельному часу.
Результат должен быть виден в ClickHouse: модельные метки уходят вперёд быстрее
реального времени, а объём событий соответствует пройденному модельному
интервалу.
## Acceptance criteria
- [ ] На ×1 поведение остаётся совместимым с обычным живым режимом.
- [ ] На ×K модельные `event_timestamp` за короткий реальный прогон покрывают
примерно `K` раз большую модельную длительность.
- [ ] Событийный бюджет считается по модельной длительности тика, а не по
реальному времени сна процесса.
- [ ] Дневной коэффициент меняется при переходе модельного времени через
дневные/ночные часы, независимо от реального часа запуска.
- [ ] ClickHouse-проверка показывает повторяемые контрольные числа при тех же
`GEN_SEED`, `T0`, скорости и настройках.
- [ ] В `generator/README.md` или `docs/OPERATIONS.md` кратко описано, что ×K
ускоряет именно модельное время стенда.
## Blocked by
- `.scratch/generator-model-time-startup-history/issues/02-model-time-to-clickhouse.md`
@@ -0,0 +1,40 @@
Status: ready-for-agent
# Восстановление state v2 от модельной точки
## Parent
`.scratch/generator-model-time-startup-history/PRD.md`
## What to build
Привести восстановление state v2 к модельному времени. Один и тот же слепок
должен уметь восстанавливаться в двух разных случаях: после сбоя, где время
действительно прошло, и при старте из стартовой истории, где продолжение идёт
от `T_end` без искусственного разрыва.
Срез должен доказать поведение не только локальными тестами состояния, но и
данными в ClickHouse: активные визиты продолжаются или закрываются по правилам
модельного времени.
## Acceptance criteria
- [ ] State сохраняет достаточно данных, чтобы после сбоя вычислить модельную
точку возобновления при ×K.
- [ ] Восстановление после короткого сбоя продолжает активные визиты и досылает
созревшие события с исходными модельными метками.
- [ ] Восстановление после долгого сбоя закрывает сильно просроченные активные
визиты без досылки остатка.
- [ ] Восстановление из стартовой истории использует `T_end` как точку
возобновления и не обрывает активные визиты из-за настенного простоя.
- [ ] Повреждённый или несовместимый state не валит сервис: генератор стартует
с чистого листа и пишет предупреждение.
- [ ] ClickHouse-проверка подтверждает, что на стыке восстановления нет дублей
событий и нет разрыва `click_id` внутри продолжающегося визита.
- [ ] После реализации выполнено саморевью worker-а и отдельное reviewer-ревью,
потому что задача меняет state/serialization и сервисное восстановление.
## Blocked by
- `.scratch/generator-model-time-startup-history/issues/03-model-speed-and-day-factor.md`
- Review gate из `PRD.md`: сквозной инвариант времени после задачи 3
@@ -0,0 +1,43 @@
Status: ready-for-agent
# Стартовая история до ClickHouse
## Parent
`.scratch/generator-model-time-startup-history/PRD.md`
## What to build
Сделать промотку прошлого: генератор быстро проходит от `T0` до `T_end`, создаёт
события за этот отрезок, сохраняет слепок состояния и манифест стартовой
истории. Эту историю нужно загрузить в ClickHouse и доказать, что живой поток
может продолжить её с `T_end`.
Это главный срез стартовой истории. Он должен проверять не только факт наличия
данных, но и форму данных: пирамиду, возвраты, длину визита, воронку и стык
между прошлым и живым продолжением.
## Acceptance criteria
- [ ] Промотка прошлого создаёт события за `[T0, T_end]`, слепок состояния и
манифест с контрольными данными.
- [ ] При одинаковых `GEN_SEED`, `T0`, `T_end` и настройках результат промотки
повторяем в пределах согласованных допусков.
- [ ] История загружается в ClickHouse штатной или явно описанной командой.
- [ ] SQL-проверка показывает здоровую пирамиду: пользователей меньше, чем
визитов, визитов меньше, чем событий.
- [ ] SQL-проверка показывает возвраты: у части пользователей больше одного
визита.
- [ ] SQL-проверка длины визита проверяет форму, а не только среднее: долю
коротких визитов, медиану и долю срезов о потолок.
- [ ] SQL-проверка воронки `/home -> товары -> /cart -> /payment ->
/confirmation` монотонно убывает, а доля дошедших до `/confirmation` в
согласованном коридоре.
- [ ] Живое продолжение после `T_end` не создаёт дублей на границе и не выглядит
как независимый второй мир.
- [ ] Подготовлены данные, команды и SQL-проверки, достаточные для внешнего
review gate по распределениям и двум путям генерации из `PRD.md`.
## Blocked by
- `.scratch/generator-model-time-startup-history/issues/04-state-v2-model-resume.md`
@@ -0,0 +1,47 @@
Status: ready-for-agent
# Стартовая история как источник аналитики
## Parent
`.scratch/generator-model-time-startup-history/PRD.md`
## What to build
Перевести штатный путь стенда на стартовую историю как источник аналитики.
Чистый стенд должен получать данные из генерации: стартовая история загружается,
STG→ODS→DDS→DM строится на ней, а Superset работает с этими витринами. Архивный
статический сид остаётся только временной кладовкой фактуры для генератора, а не
источником аналитического контура.
Срез не требует финальной ручной оценки красоты дашбордов, но должен дать
техническое доказательство: витрины и датасеты не пустые, контрольные числа
берутся из генерации.
Границы среза: штатный путь стенда и документы запуска. Переписывание уроков,
новые панели и улучшение формы дашбордов остаются follow-up, если по ходу не
окажутся маленькой обязательной правкой для запуска.
## Acceptance criteria
- [ ] Штатная команда запуска чистого стенда создаёт или загружает стартовую
историю и прогоняет её до DM-витрин.
- [ ] `kafka_load_dag` или заменяющий его путь больше не использует архивный
`data/*.jsonl` как источник аналитики.
- [ ] ClickHouse-проверки из задачи 5 доступны как повторяемая команда для
координатора или CI.
- [ ] Основные DM-витрины, на которых стоят дашборды, непустые и показывают
данные генерации.
- [ ] Superset-датасеты и дашборды технически открываются на данных генерации;
ручная оценка формы графиков остаётся финальной HITL-приёмкой.
- [ ] `README.md`, `docs/OPERATIONS.md` и `generator/README.md` больше не
описывают архивный сид как основной источник аналитики.
- [ ] Если уроки или дашборды требуют нетривиальной переделки, создан follow-up
issue вместо расширения этой задачи.
- [ ] Описан повторный чистый прогон: какие данные очищаются и какие команды
выполняются, чтобы координатор мог надёжно перепроверить результат.
## Blocked by
- `.scratch/generator-model-time-startup-history/issues/05-startup-history-backfill-to-clickhouse.md`
- Review gate из `PRD.md`: распределения и два пути генерации после задачи 5
@@ -0,0 +1,61 @@
# Handoff: задачи по модельному времени и стартовой истории
Дата: 2026-06-14
Жанр: одноразовый handoff по ADR-0003.
## Что сделано
Создан рабочий набор артефактов для следующей фазы работ:
- `.scratch/generator-model-time-startup-history/PRD.md`
- `.scratch/generator-model-time-startup-history/issues/01-time-and-startup-history-contract.md`
- `.scratch/generator-model-time-startup-history/issues/02-model-time-to-clickhouse.md`
- `.scratch/generator-model-time-startup-history/issues/03-model-speed-and-day-factor.md`
- `.scratch/generator-model-time-startup-history/issues/04-state-v2-model-resume.md`
- `.scratch/generator-model-time-startup-history/issues/05-startup-history-backfill-to-clickhouse.md`
- `.scratch/generator-model-time-startup-history/issues/06-generated-history-as-analytics-source.md`
Артефакты режут работу на 6 последовательных issue и 2 review gate. Главная
идея: каждый кодовый срез должен подтверждаться через ClickHouse, а не только
локальными тестами генератора. Финальная проверка дашбордов глазами остаётся в
конце.
## Важные решения
- Координатор не берёт `/goal` на всю цепочку: один worker получает один issue.
- Worker работает через `/tdd`, не коммитит и не реализует следующие задачи.
- После реализации worker делает саморевью без правок.
- Координатор классифицирует находки и коммитит сам.
- После задачи 3 нужен review gate по сквозному инварианту времени.
- После задачи 5 нужен review gate по распределениям и двум путям генерации.
- Для этих review gate по возможности нужен reviewer другой родословной: это
следует из `docs/research/2026-06-11-subagent-coordinator-experiment.md`.
## Что важно не потерять
- В задаче 1 нужно зафиксировать durable-контракт, а не оставить решение только
в комментарии к issue.
- При ×K восстановление после сбоя нельзя считать простым `datetime.now()`: нужна
сохранённая связка модельного и настенного времени.
- Стартовая история должна быть парным артефактом: события, слепок состояния и
манифест.
- Задача 6 специально сужена до штатного пути стенда и документов запуска.
Уроки, новые панели и улучшения дашбордов уходят в follow-up, если окажутся
нетривиальными.
## Suggested skills
- `to-issues` — если понадобится переразбить или опубликовать дополнительные
issue.
- `tdd` — основной режим работы worker-а над каждым кодовым issue.
- `conventional-commits` — перед каждым коммитом координатора.
- `claude-team-review` или другой внешний reviewer — на двух review gate.
- `handoff` — если работа прерывается между issue или после review gate.
## Следующий шаг
Начать с
`.scratch/generator-model-time-startup-history/issues/01-time-and-startup-history-contract.md`.
Это HITL-задача: нужно закрепить интерфейс модельного времени, манифест
стартовой истории, правило границы `T_end` и способ повторяемой проверки в
ClickHouse.