# Судьба заказа Резолюция развилки [«Расхождения A–D и опоздания: механика, доли и что обещано»](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/72). **Рамка.** Расхождение — не грязь и не шум, а часть мира: судьба заказа, решённая при его рождении и уложенная в окно K целиком. **Два подпотока дня.** Заказная сторона — судьба заказа: исход, моменты, дельта, опоздание. Событийная сторона — порча событийного потока: потеря и дубль. Довод за разделение — различимость по описи: правка заказной механики не двигает хеши событий, правка событийной не двигает байты слепка, и по покрасневшим хешам видно, какую сторону трогали. Прежние имена `DISCREPANCIES` и `LATECOMERS` решения не переживают — они названы по классам витрины, а компонент называет часть мира; новые стороны занимают те же позиции, имена — при реализации. Отклонено: *один компонент на всю судьбу* — правка событийной механики молча меняла бы байты слепка; *компонент на класс* — пять имён под ручки калибровки, которые крутятся разом. **Правило формы, без которого разделение не работает: броски заказной стороны делаются на полную длину дня, а не на отобранных заказах.** Иначе длина броска становится функцией доли, и правка одной доли перебрасывает весь подпоток после себя. Изоляцию даёт форма броска, а не число подпотоков. **Путь по статусам.** Три исхода, все внутри окна: **оплачен**; **оплачен и отменён**; **не оплачен и отменён**. Инвариант на выходе из окна: заказ либо `paid`, либо `cancelled`; `created` — только промежуточное состояние. За окном будущего у заказа нет, а заказ, навсегда застрявший в `created`, — модельная небрежность, которой в выгрузке живого магазина соответствия нет. Поэтому нового значения `mismatch_class` не нужно: `cancelled` покрывает обе дороги отмены (шестое значение занято `awaiting_order`). **Форма броска.** 1. **Исход** — таблица долей из трёх строк; доля неоплаченных пишется явной строкой, а не оставляется читателю складывать хвост в уме. 2. **Моменты** — таблица целых весов «сколько часов от рождения — с каким весом», строки 0…143, плюс равномерная секунда внутри часа — чтобы разности времён аудита не давали точных равенств (урок правки #50). 3. Моментов бросается **всегда два, на полную длину дня**; у одномоментных исходов второй выбрасывается. Где их два по существу, ранний считается оплатой — порядок выходит сортировкой, условной точки отсчёта не нужно. 143 часа — самый узкий край окна: у заказа, рождённого в конце суток, до последнего его слепка 144 часа. Таблица кончается там, где кончается окно у самого невезучего: вылезти нечему, сторожа не нужно. Цена — заказ, рождённый в начале суток, не использует почти сутки своего окна; в хвосте таблицы веса мизерные, в данных это не видно. Форма из #71 — «вес за краем окна означает „не оплачен никогда“» — этим отменена: такой заказ теперь отменяется, а край окна не выражается числом часов — иначе доля неоплаченных стала бы функцией часа покупки, и менти нашёл бы этот наклон первым же разрезом. **Доли.** Ориентир мастер-спеки ~5% читается как доля отменённых вообще; как она делится между двумя дорогами — строки таблицы исходов. Точные числа — калибровка этапа 7; проверок вида «отмен от 4 до 6 процентов» не заводим. **Что из двух дорог видно.** В `dds.order` дороги неразличимы — там последняя версия; различает их история версий: сырьё STG и физические версии `ods.order_snapshot` до фоновых слияний, а в витринах — выручка дня, которая сначала выросла, потом убыла. Полное различение не обещано: слепок — состояние на границе суток, и оплата с отменой в один день в сырье неразличимы; то же у сильно опоздавших, приехавших уже терминальными. Точную форму этого урока решает этап 4. Отклонено: *отмена только после оплаты* — неоплаченному некуда деться, кроме как остаться брошенным; *мгновенная отмена при рождении* — «дыхание» окна на отменах исчезает; *отмен нет вовсе* — страховочный срез 1, он в резерве.