diff --git a/.scratch/feature-data-generator/issues/01-minimal-connected-visit.md b/.scratch/feature-data-generator/issues/01-minimal-connected-visit.md new file mode 100644 index 0000000..be94353 --- /dev/null +++ b/.scratch/feature-data-generator/issues/01-minimal-connected-visit.md @@ -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 + diff --git a/.scratch/feature-data-generator/issues/02-visit-page-path-and-monotonic-time.md b/.scratch/feature-data-generator/issues/02-visit-page-path-and-monotonic-time.md new file mode 100644 index 0000000..7a76488 --- /dev/null +++ b/.scratch/feature-data-generator/issues/02-visit-page-path-and-monotonic-time.md @@ -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 + diff --git a/.scratch/feature-data-generator/issues/03-tick-stream-with-active-visits.md b/.scratch/feature-data-generator/issues/03-tick-stream-with-active-visits.md new file mode 100644 index 0000000..2caba4f --- /dev/null +++ b/.scratch/feature-data-generator/issues/03-tick-stream-with-active-visits.md @@ -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 + diff --git a/.scratch/feature-data-generator/issues/04-user-population-and-returns.md b/.scratch/feature-data-generator/issues/04-user-population-and-returns.md new file mode 100644 index 0000000..e5fdc0f --- /dev/null +++ b/.scratch/feature-data-generator/issues/04-user-population-and-returns.md @@ -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 + diff --git a/.scratch/feature-data-generator/issues/05-intensity-and-flow-calibration.md b/.scratch/feature-data-generator/issues/05-intensity-and-flow-calibration.md new file mode 100644 index 0000000..a8773f2 --- /dev/null +++ b/.scratch/feature-data-generator/issues/05-intensity-and-flow-calibration.md @@ -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 + diff --git a/.scratch/feature-data-generator/issues/06-state-v2-and-restart.md b/.scratch/feature-data-generator/issues/06-state-v2-and-restart.md new file mode 100644 index 0000000..c649e28 --- /dev/null +++ b/.scratch/feature-data-generator/issues/06-state-v2-and-restart.md @@ -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 + diff --git a/.scratch/feature-data-generator/issues/07-service-integration-and-docs.md b/.scratch/feature-data-generator/issues/07-service-integration-and-docs.md new file mode 100644 index 0000000..c722fd7 --- /dev/null +++ b/.scratch/feature-data-generator/issues/07-service-integration-and-docs.md @@ -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 + diff --git a/.scratch/handoffs/2026-06-11-generator-issues-ready.md b/.scratch/handoffs/2026-06-11-generator-issues-ready.md new file mode 100644 index 0000000..24ce751 --- /dev/null +++ b/.scratch/handoffs/2026-06-11-generator-issues-ready.md @@ -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` — при фиксации следующих изменений.