docs(glossary): четыре термина переименованы, world.md и stand.md вычитаны

- Зачем:
  - справочники читает человек со стороны, а «пульт мира», «опись мира»,
    «работник» и «сырьё» звучали шуткой или калькой времён разработки
    (тикет #214, выбор владельца).
- Что:
  - CONTEXT.md: статьи «Паспорт мира», «Даги модельного времени»,
    «Шаговый даг», «Сырые данные», старые слова в строках «Избегать»;
    пометки в ADR 0005, 0008, 0009 без переписывания решений.
  - замены по README, справочникам, путеводителю, лабам, спекам,
    комментариям дагов и SQL, тегу дага и панели Grafana; имена в коде
    не тронуты.
  - world.md и stand.md: 35 находок вычитки внесены, регистр выровнен.
- Проверка:
  - make config-test; make lint в корне и в generator/; make test в
    generator/ (437 passed); скрипт ссылок из #212 пуст; grep старых
    слов вне ADR, research и CONTEXT.md пуст.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QBCtU38qSHg5DvgtnKXcW
This commit is contained in:
ddadminandClaude Fable 5.1 committed 2026-09-02 16:46:50 +03:00
1 parent 86ad8afaf2
commit 59d8c83b17
54 files changed
+794 -776

No files matched your search

+132 -139
View File
@@ -41,10 +41,10 @@
конструкция внутри оправдана только наблюдаемым эффектом: без него это
сложность, за которую никто не заплатил.
- **Повторимы должны быть эффекты, а не конкретные числа.** Правка свойств
мира сдвигает почти все числа разом — генератор случайных чисел выдаёт
другую последовательность. Опираться на конкретные числа поэтому нечем.
Хеши описи обещают не постоянство чисел, а то, что их сдвиг не пройдёт
молча: пересобрал опись — увидел diff.
мира сдвигает почти все числа разом — генератор случайных чисел выдаёт другую
последовательность. Опираться на конкретные числа поэтому нечем. Хеши паспорта
обещают не постоянство чисел, а то, что их сдвиг не пройдёт молча: пересобрал
паспорт — увидел diff.
- **Цена ошибки здесь мала.** В худшем случае испорчен урок, и чинится он
правкой генератора после взгляда на получившиеся распределения. Оборона,
которая дороже ошибки, не заводится.
@@ -59,15 +59,15 @@
модельный день D — функция (зерно, D). Между прогонами живут только зерно
и позиция на оси времени.
- **Детерминизм до байта.** Одно зерно — побайтово тот же снимок; сверка —
хешами описи. Транспорт (офсеты Kafka, темп) — вне обещания.
хешами паспорта. Транспорт (офсеты Kafka, темп) — вне обещания.
- **Схема — контракт генератора.** Python-модуль с чистыми данными;
хранилище строится по рендеренной документации, границу сторожит строгий
приём на стороне хранилища.
- **Один сериализатор, глупые приёмники.** День-функция выдаёт канонические
байты; приёмники — файл, Kafka пачкой, Kafka с темпом.
- **Числа.** Средний день ~50 тыс. событий; эталонный снимок совпадает со
стартовым миром — 8 дней;
в git — только опись мира; автоматических порогов по времени нет.
стартовым миром — 8 дней; в git — только паспорт мира; автоматических порогов
по времени нет.
## 1. Модель мира
@@ -109,23 +109,21 @@
начинается в D0) — только дают, кому возвращаться в первые дни: дневная
аудитория на полке с самого D0, разгона «пустого магазина» нет.
- **Гарантия двухкуковых пар — назначенные заказы в плане.** Единица
здесь — человек, не кука: план помечает часть людей покупателями
(доля — раздел 9), и 15% покупателей (мастер-спека, раздел 5) получают
вторую куку. Обе куки пары принадлежат одному человеку одной когорты;
вторая рождается в пределах его окна активности, без фиксированного
зазора — по тому же затухающему профилю, что и возвраты (уточнение при
исполнении #38, 2026-08-02): куку человек заводит, пока ещё ходит.
Равные шансы по всему окну означали бы вторую куку у давно ушедшего
человека — и вчетверо меньше пар, реализованных внутри снимка.
Каждой паре план назначает дни гарантированных заказов: по
одному на куку, из дней активности этой куки, на оси от D0 и позже;
человеку предыстории, чьё окно активности таких дней не оставляет,
пара не назначается. День-функция обязана назначенные заказы
реализовать; остальные покупки — вольные, их решает генератор торговых
событий (#40). План считает пары, реализованные в запрошенном горизонте;
опись это число не хранит — оно растёт вместе с миром. Условность в данных
не видна: дни назначены той же случайностью, просто брошенной планом один
раз.
здесь — человек, не кука: план помечает часть людей покупателями (доля —
раздел 9), и 15% покупателей (мастер-спека, раздел 5) получают вторую куку.
Обе куки пары принадлежат одному человеку одной когорты; вторая рождается в
пределах его окна активности, без фиксированного зазора — по тому же
затухающему профилю, что и возвраты (уточнение при исполнении #38,
2026-08-02): куку человек заводит, пока ещё ходит. Равные шансы по всему окну
означали бы вторую куку у давно ушедшего человека — и вчетверо меньше пар,
реализованных внутри снимка. Каждой паре план назначает дни гарантированных
заказов: по одному на куку, из дней активности этой куки, на оси от D0 и
позже; человеку предыстории, чьё окно активности таких дней не оставляет, пара
не назначается. День-функция обязана назначенные заказы реализовать; остальные
покупки — вольные, их решает генератор торговых событий (#40). План считает
пары, реализованные в запрошенном горизонте; паспорт это число не хранит — оно
растёт вместе с миром. Условность в данных не видна: дни назначены той же
случайностью, просто брошенной планом один раз.
- **Своя ось модельного времени.** Ось событий начинается в
фиксированный день D0 (понедельник — см. раздел 5); реальный
календарь в модели не участвует. В `EventDate`/`UTCEventTime` дни оси
@@ -133,10 +131,10 @@
зависящая (значение — раздел 9). Между прогонами живут только зерно и
позиция на оси: выключенный ноутбук — мир замер, потом продолжил.
- **Два режима движения по одной оси.** Пошаговый — базовый для лаб: старт
с эталонного снимка, дальше «прожить следующий день» — явное действие.
Живой день — текущий день проигрывается с ускорением, дашборд и мониторинг
«дышат»; включается по требованию — постоянным фоном идёт, только пока
включён выключатель пульта ([ADR 0009](../adr/0009-world-control.md)).
с эталонного снимка, дальше «прожить следующий день» — явное действие. Живой
день — текущий день проигрывается с ускорением, дашборд и мониторинг «дышат»;
включается по требованию — постоянным фоном идёт, только пока включён
выключатель `world_live` ([ADR 0009](../adr/0009-world-control.md)).
- **Граница суток — единственный структурный шов.** Сессии режутся по ней,
дневная партиция самодостаточна; в конце модельного дня — слепок заказов.
День проживается целиком, полдня не бывает: недожитый из-за обрыва день
@@ -148,14 +146,13 @@
Отклонено с доводами:
- *Мутирующее состояние мира* («мир стареет»): ломает параллельность по
дням, требует чекпоинтов, счётчики описи узнаваемы только постфактум;
ни один урок стенда на старении не стоит.
дням, требует чекпоинтов, счётчики паспорта узнаваемы только постфактум; ни
один урок стенда на старении не стоит.
- *Чистая функция без слоя состава*: глобальные инварианты пришлось бы
выводить в каждом дне заново — тот же план мира, но неявный и размазанный.
- *Привязка модельного времени к реальному календарю* (T-1 с догоном):
конфликтует с ускорением ×60 — за вечер мир уезжает в будущее — и делает
даты эталонного мира зависимыми от даты запуска, опись теряет
воспроизводимость.
конфликтует с ускорением ×60 — за вечер мир уезжает в будущее — и делает даты
эталонного мира зависимыми от даты запуска, паспорт теряет воспроизводимость.
Отклонено при исполнении #38 (2026-08-02):
@@ -170,9 +167,9 @@
константы — потолка одновременно живущих кук, которого в жизни нет и
который менти нечем объяснить.
- *Вероятностная гарантия пар* («почти наверняка купит с обеих кук»): не
гарантия — однажды опись покраснеет, а чинить нечем, кроме смены
зерна; при этом несклеенная пара в данных неотличима от двух незнакомцев,
так что реализм этой лотереи невидим.
гарантия — однажды паспорт покраснеет, а чинить нечем, кроме смены зерна; при
этом несклеенная пара в данных неотличима от двух незнакомцев, так что реализм
этой лотереи невидим.
- *Покупка пары в первый визит куки*: гарантия железная и дешёвая, но узор
«все пары покупают в первый день» виден в данных ровно там, куда лаба
склейки смотрит пристальнее всего. Условность допустима, пока она не
@@ -185,31 +182,29 @@
- **Обещание — содержимое до байта.** Два прогона с одним зерном дают тот же
набор событий: те же `WatchID`/`VisitID`, поля, метки модельного времени.
Снимок при пересборке побайтово совпадает: канонический порядок ключей и
строк; сверка — по хешам описи, а два локально пересобранных снимка
сравнимы обычным diff — пустой означает «ничего не изменилось». Вне
обещания — транспорт: офсеты и партиции Kafka, какая нода прочитала,
`_load_ts`, темп живого дня.
строк; сверка — по хешам паспорта, а два локально пересобранных снимка
сравнимы обычным diff — пустой означает «ничего не изменилось». Вне обещания —
транспорт: офсеты и партиции Kafka, какая нода прочитала, `_load_ts`, темп
живого дня.
- **Условия обещания.** Детерминизм держится при зафиксированном `uv.lock`
и внутри канонического контейнера — то есть везде Linux, на маке и в WSL
тоже; единственная переменная — архитектура CPU. Истина — CI на Linux; сходимость любой машины проверяет
скрипт «пересгенерируй день N — сравни хеш с описью». Расхождение на
любой платформе — баг генератора, а не допуск.
и внутри канонического контейнера — то есть везде Linux, на маке и в WSL тоже;
единственная переменная — архитектура CPU. Истина — CI на Linux; сходимость
любой машины проверяет скрипт «пересгенерируй день N — сравни хеш с
паспортом». Расхождение на любой платформе — баг генератора, а не допуск.
- **Раздача зерна — иерархией подпотоков.** Корневое зерно → подпоток
состава мира, ветвящийся по номеру дня на когорты плана (состав
спрашивается по дням — раздел 1; уточнение при исполнении #38).
Дни предыстории отрицательны, а позиция в дереве — неотрицательное
целое, поэтому у предыстории своя ветвь состава, отдельная от оси
(уточнение при исполнении #38, 2026-08-02);
(зерно, день) → подпоток дня → именованные подпотоки компонентов: трафик,
торговые события, заказная и событийная стороны (судьба заказов и порча
событийного потока) — в фиксированном порядке (уточнение [судьбой
заказа](../architecture/orders/fate.md): прежние «расхождения» и
«опоздания» были названы по классам витрины, а компонент называет часть
мира).
По построению: параллельный прогон равен последовательному; продление
истории днём N+1 не трогает дни 1…N; правка одного компонента меняет
только его часть снимка — в описи меняются хеши только затронутых
дней, дифф двух локальных пересборок читаем.
состава мира, ветвящийся по номеру дня на когорты плана (состав спрашивается
по дням — раздел 1; уточнение при исполнении #38). Дни предыстории
отрицательны, а позиция в дереве — неотрицательное целое, поэтому у
предыстории своя ветвь состава, отдельная от оси (уточнение при исполнении
#38, 2026-08-02); (зерно, день) → подпоток дня → именованные подпотоки
компонентов: трафик, торговые события, заказная и событийная стороны (судьба
заказов и порча событийного потока) — в фиксированном порядке (уточнение
[судьбой заказа](../architecture/orders/fate.md): прежние «расхождения» и
«опоздания» были названы по классам витрины, а компонент называет часть мира).
По построению: параллельный прогон равен последовательному; продление истории
днём N+1 не трогает дни 1…N; правка одного компонента меняет только его часть
снимка — в паспорте меняются хеши только затронутых дней, дифф двух локальных
пересборок читаем.
- **Механизм подпотоков — `numpy.random.SeedSequence`.** Сверено через
Context7 по документации numpy (2026-08-01): `spawn(n)` порождает детей
расширением `spawn_key`, потомок полностью определяется парой
@@ -223,8 +218,8 @@
представление в клиентском `purchase` (урок мастер-спеки о расхождениях).
- **Канонический seed и паспорт мира.** Эталонный мир собирается одним
каноническим зерном — константой репозитория; свои зёрна менти крутит без
гарантий описи. Опись хранит паспорт мира — зерно и версию
генератора; чек-скрипты сверяют паспорт раньше счётчиков.
гарантий паспорта. В шапке паспорта лежат зерно и версия генератора;
чек-скрипты сверяют шапку раньше счётчиков.
- **Суточный профиль интенсивности задаёт день-функция.** Форма — волны:
ночной провал, обеденный и вечерний пики, различие будней и выходных;
пики — до ~2× среднего. С детерминизмом профиль совместим: это часть
@@ -241,8 +236,8 @@
«параллельно равно последовательно» недостижимо.
- *Обещание детерминизма поверх обновления зависимостей*: numpy сознательно
улучшает алгоритмы распределений между версиями (NEP 19), Faker меняет
словари. Фиксация — `uv.lock`; обновление зависимостей — осознанная
пересборка описи одним PR.
словари. Фиксация — `uv.lock`; обновление зависимостей — осознанная пересборка
паспорта одним PR.
## 3. Контракт схемы
@@ -289,9 +284,9 @@
- **Один канонический сериализатор, глупые приёмники.** День-функция выдаёт
упорядоченный поток канонических байтов — единственное место, где событие
превращается в JSON. Приёмники не знают о содержимом: файл (локальный кэш
для пересборки и проверок описи), Kafka пачкой — пакетный режим,
Kafka с темпом ×60 — живой день. Новых топиков нет.
превращается в JSON. Приёмники не знают о содержимом: файл (локальный кэш для
пересборки и проверок паспорта), Kafka пачкой — пакетный режим, Kafka с темпом
×60 — живой день. Новых топиков нет.
- **Одно событие — одно сообщение Kafka.** «Пачкой» относится к темпу
отправки, а не к упаковке: приёмник шлёт события подряд без пауз, но каждое
отдельным сообщением. Контракт транспорта, не деталь реализации — сторона
@@ -299,9 +294,9 @@
([ADR 0005](../adr/0005-event-ingestion.md)), поэтому склейка нескольких
событий в одно сообщение сломала бы разбор целиком.
- **Даты и время на проводе — ISO-8601.** `EventDate` уезжает как `2026-06-01`,
`UTCEventTime` — как `2026-06-01T12:34:56Z`. Довод — читаемость сырья: весь
смысл слоя STG в том, что менти открывает колонку `raw` в обычном клиенте и
разбирает событие глазами, а число эпохи этот урок убивает. Колонка
`UTCEventTime` — как `2026-06-01T12:34:56Z`. Довод — читаемость сырых данных:
весь смысл слоя STG в том, что менти открывает колонку `raw` в обычном клиенте
и разбирает событие глазами, а число эпохи этот урок убивает. Колонка
`ecommerce` — строка, внутри которой лежит экранированный JSON, как отдаёт
Метрика.
@@ -321,9 +316,9 @@
первым. Записана форма всё равно здесь — иначе каждый выберет своё, и
разойдётся это уже после приёмки.
- **Рабочий выбор сериализатора — orjson**: быстрее stdlib json в 5–14 раз,
numpy-массивы и datetime сериализует нативно (заметка исследования #31).
Смена библиотеки меняет канонические байты, поэтому проходит как
обновление зависимости: осознанная пересборка описи одним PR.
numpy-массивы и datetime сериализует нативно (заметка исследования #31). Смена
библиотеки меняет канонические байты, поэтому проходит как обновление
зависимости: осознанная пересборка паспорта одним PR.
- **Промежуточные файлы не хранятся.** Файл дня — кэш чистой функции:
потерял — пересчитал. В git снимок не попадает (раздел 5).
- **Обрыв любого режима — переигровка дня целиком**; дедуп склеивает
@@ -341,7 +336,7 @@
- *Отдельный топик / Kafka как хранилище дней*: офсеты и партиции вне
обещания детерминизма, retention конечен, в git топик не положишь, хеш с
описью не сверишь; Kafka на стенде — труба, не хранилище (раздел 7
паспортом не сверишь; Kafka на стенде — труба, не хранилище (раздел 7
мастер-спеки).
- *Файл как обязательная станция доставки*: доигрывание обрыва уже решено
через дедуп, канон держит единственный сериализатор, а не диск; файл
@@ -360,27 +355,25 @@
~2× среднего, будни/выходные; ≈8–12 тыс. сессий, 6–8 тыс. посетителей —
правдоподобный средний магазин.
- **Эталонный снимок совпадает со стартовым миром — 8 дней**: понедельник
по понедельник, полная неделя и один закрытый день за окном K = 7.
Обещание в 14 дней снято на этапе 7 (решение владельца 2026-08-30):
у дней 8–13 не нашлось читателя — лабы проигрывают мир дальше без описи,
транспорт байты с описью не сверяет, а проверке «пересгенерируй день N —
сравни хеш» день 3 годится так же, как день 13. Замеры и тесты, меряющие
мир на окне в две недели, не меняются: мир — функция без края, окну
замера опись не нужна. Удлинение описи остается дешевым ходом
(пересборка) и делается, когда читатель появится — например, если
растяжке `classes_vs_inventory` понадобится сверять больше одного
закрытого дня.
- **В git — только опись, снимок не хранится.** Снимок генерируется при
по понедельник, полная неделя и один закрытый день за окном K = 7. Обещание в
14 дней снято на этапе 7 (решение владельца 2026-08-30): у дней 8–13 не
нашлось читателя — лабы проигрывают мир дальше без паспорта, транспорт байты с
паспортом не сверяет, а проверке «пересгенерируй день N — сравни хеш» день 3
годится так же, как день 13. Замеры и тесты, меряющие мир на окне в две
недели, не меняются: мир — функция без края, окну замера паспорт не нужен.
Удлинение паспорта остаётся дешёвым ходом (пересборка) и делается, когда
читатель появится — например, если растяжке `classes_vs_inventory` понадобится
сверять больше одного закрытого дня.
- **В git — только паспорт, снимок не хранится.** Снимок генерируется при
создании мира и в проверках генератора: артефакт — кэш чистой функции, кэш в
git не хранят. Опись несёт паспорт мира, счётчики и хеши по дням; проверки
«пустой git diff» и «пересгенерируй день N — сравни хеш» живут на ней.
Первый `make up` пустого стенда — живая демонстрация детерминизма; готовый мир
повторный подъём не пересчитывает. Честная потеря —
страховка на случай платформенного бага: раньше менти с расходящимися
байтами мог взять готовый снимок из git, теперь он упрётся в красный чек
описи; смягчение — дисциплина целочисленной случайности (раздел 2):
расхождения amd64/arm64 сняты устройством, а не сторожем. CI ради одного
прогона не заводится (решение владельца 2026-08-30).
git не хранят. Паспорт несёт шапку, счётчики и хеши по дням; проверки «пустой
git diff» и «пересгенерируй день N — сравни хеш» живут на нём. Первый `make
up` пустого стенда — живая демонстрация детерминизма; готовый мир повторный
подъём не пересчитывает. Честная потеря — страховка на случай платформенного
бага: раньше менти с расходящимися байтами мог взять готовый снимок из git,
теперь он упрётся в красный чек паспорта; смягчение — дисциплина целочисленной
случайности (раздел 2): расхождения amd64/arm64 сняты устройством, а не
сторожем. CI ради одного прогона не заводится (решение владельца 2026-08-30).
- **Живой день — ×60 по умолчанию**: модельные сутки за 24 реальные минуты,
суточная волна разворачивается на глазах; темп в среднем ~35 событий/с,
в пиковые часы сильных дней — до ~100. Число —
@@ -399,7 +392,7 @@
| Операция | Ориентир |
|---|---|
| Генерация одного дня | 1,7–2,8 с (замер 7 августа 2026 года) |
| Пересборка эталонного мира (8 дней + опись, без транспорта) | 20,5 с (замер 30 августа 2026 года) |
| Пересборка эталонного мира (8 дней + паспорт, без транспорта) | 20,5 с (замер 30 августа 2026 года) |
| Заливка стартового мира при `make up` (8 дней, Kafka → матвью → ODS) | 22,5 с (замер 7 августа 2026 года) |
| Лаг живого дня | секунды |
@@ -460,9 +453,9 @@
- **Раздел 1.4**: «из контракта выводятся DDL и валидация» заменено на data
contract — хранилище пишется по документации, границу сторожит строгий
приём (раздел 3 здесь).
- **Раздел 8**: артефакт `data/startup_history/` в git заменён описью;
снимок генерируется на месте (раздел 5 здесь). Туман «политика
версионирования артефакта» закрыт этим же ходом: версионируется опись.
- **Раздел 8**: артефакт `data/startup_history/` в git заменён паспортом;
снимок генерируется на месте (раздел 5 здесь). Туман «политика версионирования
артефакта» закрыт этим же ходом: версионируется паспорт.
- **Раздел 11**: пункт «до этапа 3 зафиксировать требования
производительности» закрыт числами раздела 5.
- Мелкие согласования там, где текст опирался на артефакт в git: источник
@@ -491,24 +484,25 @@
теперь есть.
- **Этап 5 (Airflow)**: живой день со стороны хранилища — обычный ETL-даг
по расписанию (~раз в 24 минуты); генератор не дорабатывается.
- **Позиция на оси времени** (хвост отдан пульту мира раньше этапа 5 —
- **Позиция на оси времени** (хвост отдан дагам модельного времени раньше этапа
5 —
[ADR 0009](../adr/0009-world-control.md))**.** Проигрыватель состояния не
хранит (раздел 9), поэтому вести позицию — работа того, кто его зовёт. Живёт
она переменной Airflow: отсутствие переменной означает, что стартовый мир
ещё не создан. В обычной жизни её ставит даг пульта, который сыграл день, —
она переменной Airflow: отсутствие переменной означает, что стартовый мир ещё
не создан. В обычной жизни её ставит шаговый даг, который сыграл день, —
значением «последний сыгранный + 1» и только по успеху. Даги жизненного цикла
используют `-1` для незавершённой очистки, `0` для чистого мира до генерации
и ставят первый несыгранный день только после приёма стартового мира
([ADR 0013](../adr/0013-world-lifecycle.md)).
Довод — генератор отдельная и заменяемая сущность, привязывать его к
хранилищу незачем. Полный `make clean` сносит метаданные Airflow вместе с
данными ClickHouse, а узкая пересборка явно сводит сохранённую позицию с
заново залитым миром.
Расхождение переменной с данными (менти почистил партицию руками) лечится
документацией, а не сторожем: постоянная сверка была бы проверкой, красной
в норме ([ADR 0002](../adr/0002-monitoring-scope.md)).
- **Этап 7 (эталонный мир)**: пересборка — это опись, не артефакт.
CI-генерация на amd64 и arm64 снята — резолюция в разделе 5.
используют `-1` для незавершённой очистки, `0` для чистого мира до генерации и
ставят первый несыгранный день только после приёма стартового мира ([ADR
0013](../adr/0013-world-lifecycle.md)). Довод — генератор отдельная и
заменяемая сущность, привязывать его к хранилищу незачем. Полный `make clean`
сносит метаданные Airflow вместе с данными ClickHouse, а узкая пересборка явно
сводит сохранённую позицию с заново залитым миром. Расхождение переменной с
данными (менти почистил партицию руками) лечится документацией, а не сторожем:
постоянная сверка была бы проверкой, красной в норме ([ADR
0002](../adr/0002-monitoring-scope.md)).
- **Этап 7 (эталонный мир)**: пересборка обновляет паспорт мира. Отдельного
артефакта у неё нет. CI-генерация на amd64 и arm64 снята — резолюция в разделе
5.
- **Будущие лабы**: перезаливка дня X пакетным режимом проигрывателя —
готовая демонстрация идемпотентности конвейера.
@@ -521,10 +515,10 @@
[ADR 0017](../adr/0017-order-numbering.md). Новые решения генератора
записывают в ADR и в спеке этапа, на котором их принимают.
Журнал собран по темам, но дата и тикет остались у каждого решения. По
журналу видно, какие границы затрагивала каждая правка: иногда она меняла
сразу план состава, воронку и каталог. При #40 это было дешево — опись еще
не собрали; позже такой ход потребовал бы пересборки описи.
Журнал собран по темам, но дата и тикет остались у каждого решения. По журналу
видно, какие границы затрагивала каждая правка: иногда она меняла сразу план
состава, воронку и каталог. При #40 это было дёшево — паспорт мира ещё не
собрали; позже такой ход потребовал бы пересборки паспорта мира.
### План состава и числа мира
@@ -547,10 +541,10 @@
покупателей ~190 в день, что дает конверсию ~2% на сессию.
- **Конфигурация мира — модуль чистых данных** (#38, 2026-08-02) рядом с
контрактом схемы: все числа мира собраны в одном месте, которое менти может
крутить. Правка модуля меняет мир, и проверка описи честно краснеет: опись
сторожит только канон. Вне модуля остается то, что мира не меняет, — свое
зерно и транспортные флаги проигрывателя. Отклонено: внешний конфиг и
переопределения окружением — переменная мира, которой нет в паспорте описи;
крутить. Правка модуля меняет мир, и проверка паспорта честно краснеет:
паспорт сторожит только канон. Вне модуля остается то, что мира не меняет, —
свое зерно и транспортные флаги проигрывателя. Отклонено: внешний конфиг и
переопределения окружением — переменная мира, которой нет в шапке паспорта;
файл-конфиг в репозитории равен модулю по смыслу, но платит загрузчиком и
валидацией (довод раздела 3 против YAML).
- **Покупатель перестает быть словом — двумя рычагами сразу** (#40, решение
@@ -749,8 +743,8 @@
четвертям цены и по медиане, потому что одни только края списка обманываются
четырьмя исключениями. Хвост соседям: словарь ClickHouse над этим файлом ещё
не построен (#37/#43) — колонку надо взять в его описание сразу, а не догонять
правкой; описи нужен хеш каталога (хвост #42) тем более, потому что теперь в
файле живёт ещё и поведение.
правкой; паспорту нужен хеш каталога (хвост #42) тем более, потому что теперь
в файле живёт ещё и поведение.
- **Доля просмотров карточек, доходящих до корзины, выросла с 7,3% до 8,6%**
(#50, 2026-08-02) и подошла к потолку вилки. Визитам вне `/cart` нужны свои
позиции, а визит с намерением должен класть почти все сравненное; обе границы
@@ -764,7 +758,7 @@
живых магазинов эта доля гуляет широко; пока она правдоподобна, сама по себе
ничего не сторожит, и подгонять поведение под ее край не надо. Настоящий
предел считается в другой валюте — дневной бюджет событий, на котором стоит
опись #42. Если будущая правка упрется в него, двигать надо бюджет и его
паспорт #42. Если будущая правка упрется в него, двигать надо бюджет и его
причины, а не долю.
### Номер заказа, промокод и деньги
@@ -933,28 +927,27 @@
подъем указал бы внутрь `.venv`: каталог был бы в образе, но модуль его не
нашел бы. Проверено в контейнере: день совпал побайтово с прогоном на машине.
### Опись мира и словарь
### Паспорт мира и словарь
- **Опись мира одна** (#42, 2026-08-07; эталонная длина — 8 дней, этап 7,
2026-08-30). Стартовый мир этапа 2 — первые восемь дней,
понедельник по понедельник: полная неделя и первый замкнутый цикл K = 7.
`data/world-inventory.json` — та самая опись, которую обещает раздел 5.
Этап 7 оставил ее восьмидневной: у хвоста в шесть дней не нашлось читателя
(резолюция — в разделе 5); вырастет она продолжением этого же файла, а не
вторым. В JSON лежат
паспорт мира — зерно, версия генератора и хеш каталога — и строки дней с
датой, числом событий и хешем. Опись собирает `make inventory`, свежесть
сторожит `test_inventory.py` тем же способом, что свежесть описания выгрузки.
Отклонено: *два файла, младший и полный* — две правды об одном мире и лишнее
слово в словаре.
- **Паспорт мира один** (#42, 2026-08-07; эталонная длина — 8 дней, этап 7,
2026-08-30). Стартовый мир этапа 2 — первые восемь дней, понедельник по
понедельник: полная неделя и первый замкнутый цикл K = 7.
`data/world-inventory.json` — тот самый паспорт, который обещает раздел 5.
Этап 7 оставил его восьмидневным: у хвоста в шесть дней не нашлось читателя
(резолюция — в разделе 5); вырастет он продолжением этого же файла, а не
вторым. В JSON лежат шапка паспорта — зерно, версия генератора и хеш каталога
— и строки дней с датой, числом событий и хешем. Паспорт собирает `make
inventory`, свежесть сторожит `test_inventory.py` тем же способом, что
свежесть описания выгрузки. Отклонено: *два файла, младший и полный* — две
правды об одном мире и лишнее слово в словаре.
- **Хеш каталога лежит в паспорте и объясняет расхождение** (#42, 2026-08-07).
Правка цены меняет мир так же молча, как правка кода. Хеши дней и без
каталожного хеша поймают смену мира; он отвечает на следующий вопрос — что
менялось: разошлись дни и каталог — CSV, только дни — код.
- **«Манифест» переименован в «опись мира», «зерновой мир» — в «стартовый мир»**
(#42, решение владельца 2026-08-07). Обычные русские слова убирают пару
«манифест / мини-манифест» и необходимость различать две сущности там, где
вещь одна.
(#42, решение владельца 2026-08-07; позднее тикет #214 сменил «опись мира» на
«паспорт мира»). Обычные русские слова убирают пару «манифест / мини-манифест»
и необходимость различать две сущности там, где вещь одна.
### Открытое на момент заморозки