From 7dcd1c9ba3afd1daa2c7f11a8b567997f9919eae Mon Sep 17 00:00:00 2001 From: Dmitry Dementiev Date: Sun, 2 Aug 2026 16:26:10 +0300 Subject: [PATCH] =?UTF-8?q?docs(generator):=20README=20=E2=80=94=20=D1=87?= =?UTF-8?q?=D0=B5=D1=80=D0=BD=D0=BE=D0=B2=D0=BE=D0=B9=20=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=20=C2=AB=D0=9A=D0=B0=D0=BA=20=D1=8D=D1=82?= =?UTF-8?q?=D0=BE=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Зачем: код генератора компактен, но нетривиален: многое в нём — соглашения, а не конструкции, и чтением они не выводятся. Ближайшая опасность конкретна — следующий этап трогает и план, и день, а вставка броска в середину функции выглядит безобидно и молча меняет весь мир. Что: цепочка от корневого зерна до строк событий; ленивость мира — когорта по требованию и предыстория до D0, отсюда «любой день собирается сам по себе»; правило порядка бросков внутри подпотока с механикой и способом обнаружения промаха; причина целочисленной случайности со ссылкой на спеку. Раздел помечен черновым: по сути верен, но на понятность читателем со стороны не выверен — выверка вместе с полным путеводителем, тикет #48. Проверка: `make lint` чист, `make test` — 353 passed; правка только в README. Co-Authored-By: Claude Opus 5 (1M context) --- generator/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/generator/README.md b/generator/README.md index 8faa725..89e5ad2 100644 --- a/generator/README.md +++ b/generator/README.md @@ -7,6 +7,33 @@ События уже есть: день-функция отдаёт по паре (зерно, D) упорядоченный поток pageview. Торговые события и запуск снаружи — за следующими тикетами. +## Как это работает + +> Раздел черновой. По сути он верен, но на понятность читателем со стороны не +> выверен: пишет его тот, кто держит устройство генератора в голове, а это +> худший судья понятности. Выверка — вместе с путеводителем, тикет #48. + +Цепочка одна и всегда та же: корневое зерно → подпотоки по позиции в дереве +→ когорта дня (кто впервые пришёл, сколько раз вернётся, чей паспорт какой) +→ аудитория дня, то есть когорта плюс возвраты когорт окна → визиты этих кук +→ строки событий. Мир при этом ленив: когорта считается по требованию, а до +D0 живёт предыстория, поэтому любой день собирается сам по себе — прожитая +история для него не нужна и на него не влияет. + +Главное правило для того, кто придёт следующим: **внутри подпотока порядок +бросков — часть контракта.** Броски раздаёт один генератор подряд, и k-й +бросок достаётся тому, кто спросил k-м. Приписать новый бросок в конец +функции безопасно: у прежних он ничего не отнимает. Вставить в середину — +значит сдвинуть все броски после него, а с ними и весь мир: события того же +дня станут другими, счётчики канонического мира разойдутся с манифестом, и +поймается это не ошибкой, а красным чеком. Ровно поэтому паспорта кук в +`plan.cohort` бросаются последними. + +Случайность целочисленная — только диапазоны и выбор по целым весам: готовые +распределения numpy расходятся между версиями и архитектурами, а обещано +побайтовое совпадение (спека, раздел 2). Отсюда `weights.py` вместо +`rng.choice` с вероятностями. + ## Что где лежит - `src/clickstream_generator/world.py` — конфигурация мира: все его числа