Files
clickstream-data-platform/docs/architecture/orders/README.md
T
ddadminandClaude Fable 5 c28f724706 feat(generator): потеря и дубль purchase (B, D) и счетчики описи
- Зачем:
  - трекер стенда был полным, и правило «деньги — по бэкенду» держалось
    на слове; классы B и D делают недосчет и пересчет трекера
    наблюдаемыми (этап 6, #184).
- Что:
  - подпоток BEACONS: точечная потеря purchase (~3%) и сюжетный дубль
    (~2%) швом после _purchases, с гарантией моста идентичностей и
    условием допуска дубля по паузе до следующего визита;
  - опись считает пять классов по приоритету спеки; фильтр
    classes_vs_inventory расширен, нулевой класс читается нулем;
  - fate.md, seeds.md, dm.md и orders/README.md приведены к имени
    BEACONS и строгому правилу допуска.
- Проверка:
  - make lint, make typecheck, make test (433 passed) и make inventory
    из generator/ — хеши слепков не изменились;
  - на стенде: make smoke, make check-clickhouse, make check-services
    зеленые; в dq_summary classes_vs_inventory и sessions_vs_reference
    pass, витрина сверки показывает lost_event и duplicate_event.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 13:13:47 -04:00

73 lines
6.2 KiB
Markdown

# Заказы бэкенда
Устройство второго источника стенда: раз в модельный день бэкенд магазина
выгружает полный слепок заказов окна изменяемости, и деньги в витринах
считаются по нему, а не по трекеру. Набор собран картой #69 (этап 3) и
правится по мере постройки.
Границы уже решены мастер-спекой [«Боевой реализм стенда
(v2)»](../../specs/2026-07-30-stand-v2-realism.md): поля слепка, окно K = 7
как константа мира, три статуса, приоритет классов расхождений, правило
«поведение и атрибуцию считаем по трекеру, деньги — по бэкенду». Рамка, перед
которой отвечает каждое решение, — «Чем меряется генератор» в [спеке
генератора](../../specs/2026-08-01-generator.md): конструкция внутри
оправдана только наблюдаемым эффектом на выходе.
## Целевая картина одним взглядом
- **Заказ — проекция, не порождение.** Торговая половина дня-функции уже
посчитала корзину, цены, купон и номер заказа; заказная половина навешивает
судьбу и собирает слепок. Ни одного нового броска в торговом подпотоке —
[откуда берётся заказ](snapshot.md).
- **Слепок дня D — чистая функция (зерно, D)**: состояние заказов, рождённых
в дни D−6…D, снятое на границе суток D|D+1. Отправляет его следующий
прогон — ночная выгрузка бэкенда за вчера; на проводе — один JSON-документ
на заказ — [слепок и его доставка](snapshot.md).
- **Судьба заказа решается при рождении** и обязана уложиться в окно K либо
не случиться вовсе. На выходе из окна заказ либо `paid`, либо `cancelled` —
[судьба заказа](fate.md).
- **Расхождения и опоздания — часть мира, а не грязь**: два подпотока —
`ORDERS` для заказной стороны и `BEACONS` для событийной; броски независимы,
пересечения выходят арифметикой, приоритет классов работает по-настоящему —
[классы расхождений и опоздание](fate.md).
- **Опись хранит только то, чего движение мира не меняет**: хеш байтов
каждого слепка и счётчики наблюдаемых классов —
[что хранит опись](inventory.md).
- **Мост к склейке**: план состава владеет человеком; его непрозрачный
`person_id` заказ показывает как `user_id`, кликстрим остаётся анонимным —
[мост к склейке](identity.md).
- **Приём — пакетный забор**: одно прямое чтение Kafka в STG, два
`INSERT SELECT` в типизированный ODS и таблицу ошибок; `ods.order`
принимает версии заказа на `ReplacingMergeTree(snapshot_date)` —
[приём из Kafka в ODS](ingestion.md).
- **Дальше заказ живёт моделью DDS** — уже по хранилищную сторону границы,
в наборе слоя: [модель заказа](../dds/order.md).
- **Стартовый мир отправляет семь слепков** (дни 0…6): у последнего прожитого
дня клики есть, а заказов нет, и график выручки дозаполняется по ходу
мира — [заказы в стартовом мире](start-world.md).
Правила, обязательные для кода этапа 3, собраны в
[правилах кода](code-rules.md).
## Открытые решения
- **Конкретные веса и доли** — таблицы исходов, моментов, задержки опоздания,
доли классов, стоимость доставки — калибровка при реализации; финальная
фиксация чисел — пересборка эталонного мира, этап 7. При пересборке правки
потребуют только числа, не устройство.
- **Контур проверок качества для расхождений** (даг DQ, `dm.dq_summary`) —
остаётся в тумане карты #69; естественное место разговора — этап 4.
- **Каноническое чтение событий `ods.event_v`** — отдельный тикет #86, к
механике заказов не привязан.
## Родословная
Собрано тикетом #87 по резолюциям развилок карты #69: приём (#70), генератор
слепков (#71), расхождения и опоздания (#72), мост к склейке (#73), место в
стартовом мире (#74), брак и версии в ODS (#80), форма записи на проводе
(#81). Решения о приёме — [ADR 0008](../../adr/0008-order-ingestion.md) и
[ADR 0010](../../adr/0010-order-versions-in-ods.md); контракт провода —
мастер-спека, раздел 2, и [исследование формата
слепка](../../research/2026-08-16-order-snapshot-wire-format.md). Форма
набора — [ADR 0011](../../adr/0011-component-docs.md).