docs(orders): горячее ревью черновика спеки

Зачем: перед вычитанием #84 черновик перечитан глазами читателя против
резолюций — текстовые огрехи сборки правятся сейчас, пока дёшево.

Что: возвращено правило «опоздание меряется от снятия слепка, не отправки»
(#71/#72); «назначенное планом не портится» сужено до честного «не теряется
и не опаздывает»; created_at в опоздании описан без слова «честный»;
уточнено, что слепки world-init отправляет команда snapshot; в §2 добавлены
пропущенные отклонённые варианты; поправлены ссылки на разделы спеки
генератора; в перечислении компонентов дня стороны названы своими
предметами.

Проверка: чтение; вычитание — #84.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 22:21:12 +03:00
co-authored by Claude Fable 5
parent 815f500127
commit a2256a6210
2 changed files with 29 additions and 18 deletions
+5 -4
View File
@@ -198,10 +198,11 @@
целое, поэтому у предыстории своя ветвь состава, отдельная от оси целое, поэтому у предыстории своя ветвь состава, отдельная от оси
(уточнение при исполнении #38, 2026-08-02); (уточнение при исполнении #38, 2026-08-02);
(зерно, день) → подпоток дня → именованные подпотоки компонентов: трафик, (зерно, день) → подпоток дня → именованные подпотоки компонентов: трафик,
торговые события, заказная и событийная стороны судьбы заказов — в торговые события, заказная и событийная стороны (судьба заказов и порча
фиксированном порядке (уточнение [спекой заказов](2026-08-16-orders.md), событийного потока) — в фиксированном порядке (уточнение [спекой
раздел 3: прежние «расхождения» и «опоздания» были названы по классам заказов](2026-08-16-orders.md), раздел 3: прежние «расхождения» и
витрины, а компонент называет часть мира). «опоздания» были названы по классам витрины, а компонент называет часть
мира).
По построению: параллельный прогон равен последовательному; продление По построению: параллельный прогон равен последовательному; продление
истории днём N+1 не трогает дни 1…N; правка одного компонента меняет истории днём N+1 не трогает дни 1…N; правка одного компонента меняет
только его часть снимка — в описи меняются хеши только затронутых только его часть снимка — в описи меняются хеши только затронутых
+24 -14
View File
@@ -70,10 +70,11 @@
в трекере — не отдельная порода, а класс B, и делает его событийная сторона в трекере — не отдельная порода, а класс B, и делает его событийная сторона
выбрасыванием события после присвоения номера (раздел 4); выбрасыванием события после присвоения номера (раздел 4);
- номер заказа общий у обеих проекций: `order_id` = клиентский `purchaseID`, - номер заказа общий у обеих проекций: `order_id` = клиентский `purchaseID`,
читаемый номер «день и порядковый номер покупки» (спека генератора, блок читаемый номер «день и порядковый номер покупки» (спека генератора,
#40); нумеруются все покупки, дошедшие до потока дня, — до всяких потерь; раздел 9); нумеруются все покупки, дошедшие до потока дня, — до всяких
потерь;
- скидка заказа выводится из промокода события по таблице «код → скидка» — - скидка заказа выводится из промокода события по таблице «код → скидка» —
числу мира, которое этап 3 берёт готовым (спека генератора, раздел 8). числу мира, которое этап 3 берёт готовым (спека генератора, разделы 8 и 9).
В модели строка заказа в базе источника создаётся синхронно с покупкой, поэтому В модели строка заказа в базе источника создаётся синхронно с покупкой, поэтому
день рождения заказа и день создания строки совпадают. Смысл полей от этого не день рождения заказа и день создания строки совпадают. Смысл полей от этого не
@@ -96,7 +97,10 @@
глазами как два производителя, каждый со своим топиком. Один прогон с двумя глазами как два производителя, каждый со своим топиком. Один прогон с двумя
выходами отклонён: экономии он не даёт (со сдвигом отправки окно слепка и выходами отклонён: экономии он не даёт (со сдвигом отправки окно слепка и
сыгранный день не пересекаются вовсе), а правило «приёмник выбирается тем, что сыгранный день не пересекаются вовсе), а правило «приёмник выбирается тем, что
для него назвали» ломает. для него назвали» ломает. Отклонены также: *отдельный пакет и образ*
библиотека на двоих ради одной команды; *генератор пишет слепок файлом, в
топик льёт даг* — второй путь доставки и второй сериализатор; *слепок едет
топиком `hits`* — убивает два режима приёма.
**Сборка окна.** Слепок дня D несёт заказы, рождённые в дни D−6…D, и собирается **Сборка окна.** Слепок дня D несёт заказы, рождённые в дни D−6…D, и собирается
переигровкой этих семи дней: заказы дня — производная всей воронки дня, переигровкой этих семи дней: заказы дня — производная всей воронки дня,
@@ -231,7 +235,7 @@
класса — разрыв воронки, на котором держится потеря, сжался бы втрое; при класса — разрыв воронки, на котором держится потеря, сжался бы втрое; при
сюжетном разрыв снова равен доле потерь. `purchaseID`, суммы и позиции у дубля сюжетном разрыв снова равен доле потерь. `purchaseID`, суммы и позиции у дубля
один в один — посчитал наивно, удвоил выручку. Дубль случается только там, где один в один — посчитал наивно, удвоил выручку. Дубль случается только там, где
до следующего визита куки есть место больше таймаута: иначе сборка сессий у до следующего визита куки остаётся запас сверх таймаута: иначе сборка сессий у
менти разошлась бы с `VisitID` — сломался бы эталон, ради которого `VisitID` менти разошлась бы с `VisitID` — сломался бы эталон, ради которого `VisitID`
в потоке лежит. Задержка дубля — секунды-минуты, короче таймаута визита, в потоке лежит. Задержка дубля — секунды-минуты, короче таймаута визита,
поэтому `VisitID` тот же. Полночь режет дубль парой — просмотр вместе с поэтому `VisitID` тот же. Полночь режет дубль парой — просмотр вместе с
@@ -247,12 +251,15 @@
не расхождение в данных; менти различить не может. Гарантия плана старше не расхождение в данных; менти различить не может. Гарантия плана старше
расхождения. расхождения.
**Опоздание — заказ прячется от ранних слепков.** `created_at` честный, но в **Опоздание — заказ прячется от ранних слепков.** `created_at` не
слепках дней d…d+δ−1 строки нет, а с d+δ она появляется в том состоянии, до подделывается — строка создана, когда заказ родился, — но в слепках дней
которого заказ дожил: отменённый на второй день и опоздавший на третий приедет d…d+δ−1 её нет, а с d+δ она появляется в том состоянии, до которого заказ
в первом же своём слепке как `cancelled` — «выгрузка догоняет жизнь». Задержка дожил: отменённый на второй день и опоздавший на третий приедет в первом же
— таблица весов из трёх строк: 0 на подавляющем весе, 1 и 2 — это и есть своём слепке как `cancelled` — «выгрузка догоняет жизнь». Задержка — таблица
«D+1/D+2» мастер-спеки. Дальше таблица не идёт: заказ с δ = 6 приехал бы ровно весов из трёх строк: 0 на подавляющем весе, 1 и 2 — это и есть «D+1/D+2»
мастер-спеки. Меряется она в днях снятия слепка, а не отправки: иначе сдвиг
отправки удвоился бы, и обещанные D+1/D+2 стали бы D+2/D+3. Дальше таблица не
идёт: заказ с δ = 6 приехал бы ровно
в одном слепке, и обещание «пропущенный день ничего не ломает» на нём в одном слепке, и обещание «пропущенный день ничего не ломает» на нём
перестало бы быть верным; при δ ≤ 2 у всякого заказа слепков не меньше пяти. перестало бы быть верным; при δ ≤ 2 у всякого заказа слепков не меньше пяти.
Легенда: заказ ушёл в ручную обработку и попал в выгрузку позже. Следствие для Легенда: заказ ушёл в ручную обработку и попал в выгрузку позже. Следствие для
@@ -263,7 +270,8 @@
**Пересечения.** Броски независимы, пересечения выходят арифметикой, приоритет **Пересечения.** Броски независимы, пересечения выходят арифметикой, приоритет
мастер-спеки работает по-настоящему. Исключений два, и оба названы выше: дубль мастер-спеки работает по-настоящему. Исключений два, и оба названы выше: дубль
решается только у выживших покупок, и назначенное планом не портится. решается только у выживших покупок, а назначенное планом не теряется и не
опаздывает — дельта и отмена ему разрешены, моста они не рвут.
Следствие для калибровки: брошенная доля и наблюдаемая в сверке — разные числа Следствие для калибровки: брошенная доля и наблюдаемая в сверке — разные числа
(часть заказов забирают победители по приоритету, часть у класса C недоступна — (часть заказов забирают победители по приоритету, часть у класса C недоступна —
однопозиционных заказов больше половины). Отклонено: *один класс на заказ* однопозиционных заказов больше половины). Отклонено: *один класс на заказ*
@@ -346,8 +354,10 @@
границе суток 7|8. Генератор играет два источника с разными темпами — поток границе суток 7|8. Генератор играет два источника с разными темпами — поток
Метрики и ночную выгрузку магазина; разные темпы дают всё остальное. Метрики и ночную выгрузку магазина; разные темпы дают всё остальное.
`world-init` играет восемь дней одним прогоном `batch --day 0 --days 8`; со `world-init` играет восемь дней одним прогоном `batch --day 0 --days 8`;
сдвигом отправки уезжают **слепки дней 0…6**. Слепок дня 7 снят на границе слепки отправляет второй запуск — команда `snapshot` того же диапазона (два
источника — два запуска, раздел 2), и со сдвигом отправки уезжают **слепки
дней 0…6**. Слепок дня 7 снят на границе
суток и уедет первым же ходом мира. Особого режима у стартового мира нет: суток и уедет первым же ходом мира. Особого режима у стартового мира нет:
правило отправки живёт в одном месте — в проигрывателе; генератору это решение правило отправки живёт в одном месте — в проигрывателе; генератору это решение
не стоит ничего. не стоит ничего.