Files
ddadminandClaude Fable 5 0d9a83d6af docs(orders): устройство заказов переехало в живой набор architecture/orders
Зачем: собранная спека заказов стала базовой документацией сервиса, а
жанр спеки-события ей мал: дата в имени врёт, целиком в контекст агента
она не влезает, а трекер с резолюциями долговечным хранилищем не
считается. Решение владельца — держать детальное устройство компонента
связным набором живых документов (ADR 0011) и совместить переезд с
проходом на вычитание (#84).

Что: docs/architecture/orders/ — индекс README и файлы по частям
устройства: проекция, слепок и доставка, судьба, классы расхождений,
опись, мост к склейке, стартовый мир, правила кода; спека приёма
переехала в ingestion.md без содержательных правок. Резы вычитания по
итогам двух слепых линий: тела разделов о проводе и приёме сведены к
указателям на мастер-спеку, исследование формата и ADR (порядок строк
слепка — единственное правило, оставшееся на месте); замеры канонического
зерна и повторы-пояснения срезаны; списки отклонённых вариантов сохранены
как долговечная запись. Датированные файлы удалены, ссылки из мастер-спеки,
спеки генератора, ADR 0008/0010, исследования формата и storage.md
перенацелены; раздел «Структура» AGENTS.md дополнен правилом подпапки.

Проверка: grep по репозиторию не находит ссылок на удалённые файлы;
все относительные ссылки внутри набора разрешаются в существующие файлы;
впереди холодная сверка «ни одно решение не потеряно» и приёмка #88.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 23:50:13 +03:00

8.0 KiB

Классы расхождений и опоздание

Резолюция развилки «Расхождения A–D и опоздания: механика, доли и что обещано». Классы и ориентиры долей — мастер-спека, раздел 4; здесь — механика каждого.

Дельта суммы (C) — вычеркнутая позиция. Товара не оказалось в наличии, позицию сняли: у заказа на одну позицию меньше, чем в клиентских массивах, а items_total меньше на её стоимость. Момента у неё нет — заказ приезжает урезанным во всех своих слепках: первый слепок снимается на границе суток, когда склад заказ уже собрал. Заказ из одной позиции дельты не получает — пустых заказов не бывает. Позиция выбирается равновероятно: корреляция со спросом на доле 1–2% статистически ненаблюдаема — менти платил бы за неё таблицей чисел мира, а увидеть не мог бы ничем. Доводы за вычёркивание: остаток — сотни рублей, он торчит в витрине сверки сам; расхождение объясняется сравнением позиций — разбором вложенного JSON и ARRAY JOIN, ровно тем навыком, ради которого позиции разбираются; история рассказывается словами без легенды про генератор. Отклонено: переоценка позиции и другое количество — дельта в десятки рублей, её надо захотеть заметить; чистая дельта без истории — тупик, объяснить нечем; врёт клиент, а не бэкенд — заказ у нас проекция той же корзины.

Потеря события (B) — точечная. Уходит строка purchase, просмотр /confirmation остаётся: события уезжают разными запросами, потерять один и сохранить другой — обычное дело. Единственный вариант, при котором потеря видна со стороны трекера: до подтверждения дошли сто, покупок девяносто семь.

Дубль события (D) — сюжетный. Обновление страницы шлёт и просмотр, и покупку. Довод не в связности легенды: точечный дубль ломал бы урок соседнего класса — разрыв воронки, на котором держится потеря, сжался бы втрое; при сюжетном разрыв снова равен доле потерь. purchaseID, суммы и позиции у дубля один в один — посчитал наивно, удвоил выручку. Дубль случается только там, где до следующего визита куки остаётся запас сверх таймаута: иначе сборка сессий у менти разошлась бы с VisitID — сломался бы эталон, ради которого VisitID в потоке лежит. Задержка дубля — секунды-минуты, короче таймаута визита, поэтому VisitID тот же. Полночь режет дубль парой — просмотр вместе с покупкой, по тому же правилу, что у подтверждения с торговым хвостом. Отклонено: обе точечные — дубль затирает урок потери; обе сюжетные — потеря перестаёт быть видна со стороны трекера.

Гарантия моста сильнее порчи. Назначенные планом покупки не теряются, и назначенные планом заказы не опаздывают: dds.identity_map строится из моста «purchase ↔ заказ», и выброшенное событие — как и заказ, не попавший ни в один снятый слепок, — уносит куку из карты. Это был бы отказ лабы склейки, а не расхождение в данных; менти различить не может.

Опоздание — заказ прячется от ранних слепков. created_at не подделывается — строка создана, когда заказ родился, — но в слепках дней d…d+δ−1 её нет, а с d+δ она появляется в том состоянии, до которого заказ дожил: отменённый на второй день и опоздавший на третий приедет в первом же своём слепке как cancelled — «выгрузка догоняет жизнь». Задержка — таблица весов из трёх строк: 0 на подавляющем весе, 1 и 2 — это и есть «D+1/D+2» мастер-спеки. Меряется она в днях снятия слепка, а не отправки: иначе сдвиг отправки удвоился бы, и обещанные D+1/D+2 стали бы D+2/D+3. Дальше таблица не идёт: заказ с δ = 6 приехал бы ровно в одном слепке, и обещание «пропущенный день ничего не ломает» на нём перестало бы быть верным; при δ ≤ 2 у всякого заказа слепков не меньше пяти. Легенда: заказ ушёл в ручную обработку и попал в выгрузку позже. Отклонено: сдвиг created_at — подделка аудита источника: день создания строки разошёлся бы с днём покупки, чьё равенство держит синхронная модель (откуда берётся заказ), заказ уехал бы в чужую партицию, и «выручка дня D» перестала бы отвечать покупкам дня D — сломалась бы та самая сверка, ради которой всё строится.

Пересечения. Броски независимы, пересечения выходят арифметикой, приоритет мастер-спеки работает по-настоящему. Исключений два, и оба названы выше: дубль решается только у выживших покупок, а назначенное планом не теряется и не опаздывает — дельта и отмена ему разрешены, моста они не рвут. Следствие для калибровки: брошенная доля и наблюдаемая в сверке — разные числа (часть заказов забирают победители по приоритету, часть у класса C недоступна — однопозиционных заказов больше половины). Отклонено: один класс на заказ — приоритет в SQL стал бы мёртвой веткой, которую менти читает как живую.