# Уборка сервиса генератора перед активными визитами

Дата: 2026-06-11
Статус: Draft
Связано: [спека математической модели](./2026-06-10-generator-math-model.md),
[спека иерархической переработки](./2026-06-09-generator-rework-hierarchical.md),
[`generator/KNOWN_ISSUES.md`](../../generator/KNOWN_ISSUES.md),
задачи `.scratch/feature-data-generator/issues/01..07`.

## Problem

После первых двух срезов новый генератор уже умеет строить связанный визит и
путь по страницам, но сервисный код начал распухать. В одном
`generator/generator.py` смешаны генеративная модель, чтение сида, тиковая
логика, Kafka, состояние, история пачек, метрики и запуск сервиса.

Следующая задача — активные визиты между тиками — добавит новый слой состояния.
Если продолжить в текущей форме, этот слой ляжет поверх временного
`generate_tick_batch()`, который набирает тик целыми визитами и не соответствует
целевой модели.

## Goals

- Разнести код генератора по понятным учебным модулям без изменения внешнего
  поведения сервиса.
- Подготовить место для задачи 03: активные визиты должны появиться в отдельном
  тиковом слое, а не внутри большого `generator.py`.
- Явно отделить временные части старой модели от контрактов, которые надо
  сохранить.
- Сохранить прежние команды запуска, Kafka-топики, формат сообщений и полезные
  метрики.

## Non-goals

- Не реализовывать активные визиты из задачи 03.
- Не добавлять популяцию пользователей, возвраты, калибровку интенсивности или
  состояние версии 2.
- Не менять DDL, ETL, витрины или Superset.
- Не делать большой перепил поведения генератора под видом уборки.

## Current state

`generator/generator.py` содержит около тысячи строк и несколько разных
ответственностей:

- `Config` — настройки;
- `EventDictionary` — чтение и индексация JSONL-сида;
- `EventGenerator` — генерация визитов, страниц, пауз и интенсивности;
- `BatchRecord`, `KafkaBatchHistory` — история пачек в Kafka;
- `GeneratorState`, `KafkaStateManager` — состояние версии 1;
- `KafkaPublisher`, `ensure_topics` — работа с Kafka;
- `GeneratorService` — метрики, запуск, основной цикл.

`generate_tick_batch()` сейчас является переходным механизмом: он добирает
событийный бюджет полными визитами. Это допустимо после задач 01-02, но должно
быть заменено в задаче 03 тиковым слоем с активными визитами.

## Options considered

- **Минимальная уборка в одном файле.** Быстро, но файл останется тяжёлым и
  следующая задача снова его раздует.
- **Разнести код по модулям.** Чище для чтения, лучше соответствует учебной
  цели и даёт место для активных визитов.
- **Сначала выбросить лишнее.** Может заметно сократить код, но требует решения,
  какие сервисные возможности больше не нужны.

## Recommended approach

Принят смешанный вариант: разнести код по модулям и по ходу явно отметить или
удалить очевидно временные части, если они не являются внешним контрактом.

Целевая форма:

- `generator/generator.py` — тонкая точка входа и совместимый фасад для старых
  импортов тестов;
- `generator/src/clickstream_generator/config.py` — конфигурация и её валидация;
- `generator/src/clickstream_generator/dictionary.py` — загрузка и индексы
  исходных JSONL;
- `generator/src/clickstream_generator/generation.py` — чистая генеративная
  модель визита, страниц и пауз;
- `generator/src/clickstream_generator/intensity.py` — расчёт бюджета активности:
  Пуассон, часовой коэффициент, jitter;
- `generator/src/clickstream_generator/runtime.py` — переходный тиковый слой до
  активных визитов;
- `generator/src/clickstream_generator/kafka_io.py` — Kafka publisher, создание
  топиков, Kafka-state и история batch;
- `generator/src/clickstream_generator/state.py` — сериализуемое состояние
  генератора;
- `generator/src/clickstream_generator/metrics.py` — Prometheus-метрики;
- `generator/src/clickstream_generator/service.py` — основной сервисный цикл.

`generator.py` остаётся фасадом, потому что тесты и часть документации уже
используют импорт `from generator import ...`. Рабочий пакет называется
`clickstream_generator`, чтобы не путать его с каталогом `generator/` и файлом
`generator.py`. Dockerfile должен копировать `src/` и выставлять
`PYTHONPATH=/app/src`.

Точное разбиение может быть чуть проще, если это уменьшит шум, но граница между
моделью генерации, тиковым runtime и Kafka-интеграцией должна быть явной.

## Decisions and rejected alternatives

- **Принято:** уборка идёт перед задачей 03. Причина: активные визиты добавляют
  новый слой состояния, и его нельзя удобно встроить в текущий монолит.
- **Принято:** внешнее поведение генератора не меняется. Цель задачи — форма
  кода, а не новая модель данных.
- **Принято:** исходники живут в `generator/src/clickstream_generator/`, а не
  россыпью в `generator/`. Причина: так структура ближе к обычному Python-пакету
  и проще для учебного чтения.
- **Принято:** `generate_tick_batch()` считать временным переходным механизмом.
  После задачи 03 тик должен выпускать созревшие события активных визитов.
- **Отклонено:** ограничиться перестановкой функций внутри `generator.py`.
  Это не решает учебную читаемость и не создаёт ясного места для следующих
  срезов.
- **Отклонено:** удалить историю пачек без отдельного решения. Её можно
  упростить или вынести, но пока не доказано, что она не нужна для демо и
  мониторинга.

## Validation

- Все существующие тесты генератора проходят.
- Импорты, которые используют тесты, либо обновлены, либо сохранены через фасад
  `generator/generator.py`.
- `generate_batch()` продолжает строить один связанный визит с монотонным
  временем, как после задач 01-02.
- Временный `generate_tick_batch()` не остаётся в чистой модели визита: он вынесен
  в переходный тиковый слой или явно подготовлен к замене задачей 03.
- Сервисный контур продолжает публиковать в те же четыре Kafka-топика:
  `browser_events`, `location_events`, `device_events`, `geo_events`.
- Dockerfile и запуск контейнера учитывают новую структуру файлов.
- Рабочий пакет импортируется как `clickstream_generator`, при этом старые
  импорты через фасад `generator.py` продолжают работать.
- В коде есть ясное место, куда задача 03 добавит активные визиты без расширения
  Kafka-слоя и без переписывания генерации одного визита.

## Documentation impact

- После реализации уборки обновить `generator/README.md`: описать новую
  структуру `src/clickstream_generator` и убрать формулировки, которые привязаны
  к одному `generator.py`.
- Если по ходу будет принято решение удалить или заменить `generator_batch_history`,
  это должно быть отдельно отражено в README и в задаче реализации.
