docs(generator): добавлены задачи реализации и handoff

- Зачем:
  - переработку steady-stream генератора нужно передать агентам как набор
    проверяемых вертикальных задач, а не как один крупный rewrite.
- Что:
  - создан локальный набор из семи ready-for-agent задач для реализации новой
    иерархической модели генератора.
  - добавлен handoff с текущим состоянием обсуждения, рекомендуемым следующим
    шагом через TDD и примером команды /goal для запуска задачи 01.
- Проверка:
  - git diff HEAD~1 --stat.
This commit is contained in:
Dmitry Dementiev
2026-06-11 10:48:37 +03:00
parent bcca8f5127
commit f0370cdb90
8 changed files with 327 additions and 0 deletions
@@ -0,0 +1,38 @@
Status: ready-for-agent
# Минимальный связанный визит в новом ядре
## What to build
Построить первый проверяемый срез нового steady-stream генератора: публичный
вызов генеративного ядра создаёт один визит, который выглядит как нормальная
единица доменной модели `пользователь -> визит -> событие`.
Визит должен выпускать несколько связанных событий: один общий `click_id`,
разные `event_id`, общий device/geo-контекст и согласованные записи для четырёх
Kafka-топиков. Kafka на этом шаге не нужна: задача проверяет форму данных на
выходе генеративного ядра.
Источник решений: `docs/specs/2026-06-09-generator-rework-hierarchical.md`,
`docs/specs/2026-06-10-generator-math-model.md`, `CONTEXT.md`.
## Acceptance criteria
- [ ] Тест через публичный интерфейс генератора создаёт один визит с несколькими
browser-событиями под одним `click_id`.
- [ ] У всех событий визита разные валидные `event_id`, а `click_id` не берётся
из исходного сида.
- [ ] Для каждого browser-события есть связанная location-запись с тем же
`event_id`.
- [ ] Для каждого события визита публикуются device- и geo-записи с тем же
`click_id`; их содержимое в рамках визита одинаковое, как в сиде.
- [ ] Один `click_id` связан ровно с одним `user_domain_id`.
- [ ] Старый тестовый контракт "одно событие = один новый click_id" удалён или
заменён на новый контракт визита.
## Blocked by
None - can start immediately.
## Comments
@@ -0,0 +1,38 @@
Status: ready-for-agent
# Путь визита по страницам и монотонное время
## What to build
Расширить минимальный визит до правдоподобного пути по страницам. Визит должен
начинаться со страницы, выбранной по стартовому распределению, дальше идти по
марковской цепочке и назначать событиям запланированные метки времени, которые
строго растут внутри `click_id`.
Задача остаётся без Kafka и без популяции пользователей: она проверяет качество
одного визита как учебного объекта и как основы будущей воронки.
Источник решений: `docs/specs/2026-06-10-generator-math-model.md`, раздел
«События и путь по страницам».
## Acceptance criteria
- [ ] Тест через публичный интерфейс генератора показывает, что
`event_timestamp` внутри одного `click_id` строго возрастает.
- [ ] Метки времени событий являются запланированными моментами визита, а не
одинаковым `now()` для всего набора событий.
- [ ] Паузы внутри визита меньше 30 минут; 95-й перцентиль на симуляции лежит в
масштабе единиц минут.
- [ ] Визит не может зациклиться бесконечно: длина ограничена потолком
`GEN_MAX_SESSION_EVENTS` или его новым эквивалентом.
- [ ] Доля визитов, дошедших до `/confirmation`, на симуляции сопоставима с
ориентиром сида около 25%.
- [ ] Визит может продолжаться после `/confirmation`; `/confirmation` не
считается обязательным последним событием визита.
## Blocked by
- `.scratch/feature-data-generator/issues/01-minimal-connected-visit.md`
## Comments
@@ -0,0 +1,36 @@
Status: ready-for-agent
# Поток по тикам с активными визитами
## What to build
Разложить визиты по тикам генератора. Визит может жить дольше одного тика:
генератор хранит активные визиты между вызовами, выпускает только те события,
чьё запланированное время наступило, и не приклеивает все события к текущему
тику.
Задача проверяет основную потоковую механику без Kafka и без восстановления
после рестарта.
Источник решений: `docs/specs/2026-06-10-generator-math-model.md`, раздел
«Раскладка по тикам».
## Acceptance criteria
- [ ] Тест через публичный интерфейс генератора показывает, что один `click_id`
может появляться в выходе нескольких последовательных тиков.
- [ ] На каждом тике выпускаются только созревшие события активных визитов.
- [ ] `event_timestamp` отражает запланированное время события, а не время
фактической отправки тика.
- [ ] Завершённые визиты больше не выпускают события в следующих тиках.
- [ ] При достижении потолка активных визитов новые рождения в этот тик
пропускаются, а бюджет не копится бесконечно.
- [ ] Конфигурация запрещает состояние, где потолок активных визитов не меньше
потолка популяции пользователей.
## Blocked by
- `.scratch/feature-data-generator/issues/02-visit-page-path-and-monotonic-time.md`
## Comments
@@ -0,0 +1,35 @@
Status: ready-for-agent
# Популяция пользователей и возвраты
## What to build
Добавить ограниченную популяцию пользователей с постоянными `user_domain_id`.
Новые визиты должны доставаться либо новым пользователям, либо возвращающимся
пользователям из популяции, доступным после кулдауна и не имеющим активного
визита.
Задача должна превратить поток из набора независимых визитов в живую модель
возвратов пользователей.
Источник решений: `docs/specs/2026-06-10-generator-math-model.md`, разделы
«Популяция пользователей» и «Визиты».
## Acceptance criteria
- [ ] На длинной симуляции получается здоровая пирамида
`users < sessions < events`.
- [ ] Один пользователь может иметь несколько `click_id` во времени.
- [ ] Один `click_id` принадлежит ровно одному `user_domain_id`.
- [ ] Пользователь не получает новый визит раньше минимального кулдауна возврата.
- [ ] Если доступных возвращающихся пользователей нет, новый визит достаётся
новому пользователю.
- [ ] Размер активной популяции не растёт выше заданного потолка; при
переполнении вытесняется давно неактивный пользователь без активного визита.
## Blocked by
- `.scratch/feature-data-generator/issues/03-tick-stream-with-active-visits.md`
## Comments
@@ -0,0 +1,39 @@
Status: ready-for-agent
# Интенсивность и калибровка потока
## What to build
Связать иерархическую модель с целевой интенсивностью потока. Старая идея
Пуассона, часового коэффициента и jitter должна задавать бюджет активности, из
которого рождаются визиты; фактические события выходят по запланированным
паузам активных визитов.
На этом шаге также нужно проверить, что параметры модели дают поток,
сопоставимый с профилем сида: длина визита около 10 событий в среднем и по
медиане, доля дошедших до `/confirmation` около 25%, межсессионные паузы
согласованы с формулой из спеки.
Источник решений: `docs/specs/2026-06-10-generator-math-model.md`, разделы
«Связка с моделью интенсивности», «Параметры» и «Критерии приёмки».
## Acceptance criteria
- [ ] Средняя интенсивность событий за длинное окно соответствует
`GEN_LAMBDA_BASE_PER_MIN * часовой коэффициент` с разумным отклонением.
- [ ] Рождения визитов рассчитываются из бюджета событий и средней длины визита,
а не из старых границ `GEN_MIN/MAX_EVENTS_PER_TICK` в прежнем смысле.
- [ ] Доля новых пользователей за длинное окно близка к `GEN_P_NEW_USER`.
- [ ] Межсессионные паузы одного пользователя не меньше кулдауна, а среднее на
дефолтах находится в районе расчёта из спеки.
- [ ] Распределение длины визита на симуляции сопоставимо с сидом: медиана около
10, среднее около 10, максимум не выше потолка.
- [ ] Воронка по шагам `/home -> товары -> /cart -> /payment -> /confirmation`
монотонно затухает на длинной симуляции.
## Blocked by
- `.scratch/feature-data-generator/issues/04-user-population-and-returns.md`
## Comments
@@ -0,0 +1,36 @@
Status: ready-for-agent
# Состояние версии 2 и рестарт
## What to build
Расширить состояние генератора до версии 2: кроме тика и состояния генератора
случайных чисел сохранять популяцию пользователей и активные визиты. После
рестарта генератор должен продолжать коротко прерванные визиты и закрывать
сильно просроченные, не теряя популяцию пользователей.
Задача проверяет поведение состояния через публичные методы сохранения и
восстановления, без реального Kafka-брокера там, где достаточно сериализации.
Источник решений: `docs/specs/2026-06-10-generator-math-model.md`, раздел
«Персистентность через рестарты».
## Acceptance criteria
- [ ] Состояние версии 2 сериализуется в JSON и восстанавливает тик, ГПСЧ,
популяцию пользователей и активные визиты.
- [ ] Старое состояние версии 1 или битое состояние не валит генератор:
фиксируется предупреждение, генератор начинает с чистого листа.
- [ ] После простоя не больше 30 минут активный визит продолжается, а созревшие
события досылаются со своими исходными запланированными метками времени.
- [ ] После долгого простоя просроченный активный визит закрывается без досылки
остатка.
- [ ] Популяция пользователей переживает простой любой длины.
- [ ] `GEN_STATE_RESET=true` явно сбрасывает состояние, как и раньше.
## Blocked by
- `.scratch/feature-data-generator/issues/05-intensity-and-flow-calibration.md`
## Comments
@@ -0,0 +1,39 @@
Status: ready-for-agent
# Подключение к сервису и документации
## What to build
Подключить новое генеративное ядро к рабочему steady-stream сервису. Генератор
должен запускаться прежними командами, писать сообщения в прежние Kafka-топики,
сохранять полезные метрики Prometheus и больше не документироваться как
концептуально сломанный источник.
На этом шаге нужно синхронизировать пользовательскую документацию и заметку об
известных проблемах с новой моделью.
Источник решений: `docs/specs/2026-06-09-generator-rework-hierarchical.md`,
`docs/specs/2026-06-10-generator-math-model.md`, `generator/README.md`,
`generator/KNOWN_ISSUES.md`.
## Acceptance criteria
- [ ] Генератор в режиме steady-stream пишет связанные сообщения в
`browser_events`, `location_events`, `device_events`, `geo_events`.
- [ ] Существующие команды запуска и остановки генератора остаются рабочими или
документация явно описывает замену.
- [ ] Метрики Prometheus продолжают показывать успешные тики, ошибки публикации
и объём отправленных событий.
- [ ] Интеграционный тест или проверка с мок-публикацией подтверждает, что
сервисный контур использует новую модель, а не старую плоскую генерацию.
- [ ] `generator/README.md` описывает новые параметры и новую модель без старых
предупреждений о сломанном `click_id`.
- [ ] `generator/KNOWN_ISSUES.md` обновлён: старый дефект закрыт или перенесён в
исторический раздел, не как актуальный блокер.
## Blocked by
- `.scratch/feature-data-generator/issues/06-state-v2-and-restart.md`
## Comments
@@ -0,0 +1,66 @@
# Handoff: генератор разбит на AFK-задачи
Дата: 2026-06-11
Ветка: `feature/data-generator`
Жанр: одноразовые леса по [ADR-0003](../../docs/adr/0003-handoffs-in-scratch.md).
## Где остановились
После обсуждения с пользователем дизайн переработки steady-stream генератора
переведён из больших спек в локальные задачи для агентов. Код генератора не
меняли.
Создан каталог задач:
- `.scratch/feature-data-generator/issues/01-minimal-connected-visit.md`
- `.scratch/feature-data-generator/issues/02-visit-page-path-and-monotonic-time.md`
- `.scratch/feature-data-generator/issues/03-tick-stream-with-active-visits.md`
- `.scratch/feature-data-generator/issues/04-user-population-and-returns.md`
- `.scratch/feature-data-generator/issues/05-intensity-and-flow-calibration.md`
- `.scratch/feature-data-generator/issues/06-state-v2-and-restart.md`
- `.scratch/feature-data-generator/issues/07-service-integration-and-docs.md`
Все задачи имеют `Status: ready-for-agent`. Разрез сделан как последовательные
вертикальные срезы, а не как слои архитектуры. Решение пользователя: идти по
этому варианту.
## Важный контекст
- Старый генератор считаем слабым прототипом, а не ценным кодом для сохранения.
Сохранять надо внешние контракты, если они полезны: топики Kafka, формат
сообщений для текущего ETL, команды запуска, метрики, идею compact-топика
состояния.
- Отдельную задачу "зафиксировать внешний контракт" не создавали: контракт
встроен в первый и последний срезы.
- Детали модели не дублировать отсюда. Источники истины:
- `docs/specs/2026-06-10-generator-math-model.md`
- `docs/specs/2026-06-09-generator-rework-hierarchical.md`
- `docs/adr/0004-steady-stream-synthetic-generator.md`
- `CONTEXT.md`
- `generator/KNOWN_ISSUES.md`
- Предыдущий handoff `.scratch/handoffs/2026-06-10-generator-spec-to-codex.md`
остаётся полезным как предыстория спек.
## Следующий шаг
Начать с задачи 01 через TDD:
1. написать один красный тест на публичное поведение "минимальный связанный
визит";
2. реализовать минимальное новое генеративное ядро без Kafka;
3. не тащить старую плоскую модель `generate_batch()`;
4. после зелёного теста переходить к следующему поведению, не писать все тесты
заранее.
Пример запуска задачи:
```text
/goal Реализовать .scratch/feature-data-generator/issues/01-minimal-connected-visit.md с использованием /tdd. Соблюдать цикл: один тест на наблюдаемое поведение → минимальная реализация → зелёный тест → остановиться и отчитаться. Не писать все тесты заранее, не реализовывать задачи 02-07.
```
## Suggested skills
- `tdd` — для реализации каждой задачи короткими циклами red-green-refactor.
- `adversarial-review` или `claude-team-review` — после реализации нескольких
срезов, чтобы сверить код с мат-спекой.
- `conventional-commits` — при фиксации следующих изменений.