- Зачем:
- ярлык snapshot_date выжившей строки доставался жребием, а объём
пересборки DDS держался на константе окна с двумя несверяемыми копиями
(ADR 0014, развилка #163).
- Что:
- ods.order_rep переведена на ReplacingMergeTree(snapshot_date): выживает
строка позднейшего слепка, ярлык стал правдивым.
- order_scope.sql выводит окно из дней последнего слепка; ORDER_WINDOW_DAYS
и параметр window_days сняты со стенда, мёртвая защита краем источника
убрана.
- документы и комментарии SQL приведены к ADR 0014: роль ODS, условие
«одна дата — один слепок», объём прогона и слепые пятна конвейера.
- Проверка:
- make lint; make rebuild-storage, затем make smoke, make check-clickhouse,
make check-services — зелёные.
- после двух слепков snapshot_date всех 1917 строк ods.order_v равен
последнему слепку заказа, расхождений ноль; деловые поля построчно
совпали с эталоном argMax по updated_at из сырья.
- dds_transform без K: первый прогон 06-01…06-07, после нового дня мира
06-02…06-08, повтор прогона содержимого не изменил.
Closes #165
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
77 lines
6.5 KiB
Markdown
77 lines
6.5 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).
|
|
- **Расхождения и опоздания — часть мира, а не грязь**: два подпотока —
|
|
заказная и событийная стороны; броски независимы, пересечения выходят
|
|
арифметикой, приоритет классов работает по-настоящему —
|
|
[классы расхождений и опоздание](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).
|
|
|
|
## Открытые решения
|
|
|
|
- **Имя подпотока событийной стороны** — вместе с её содержимым на этапе 6;
|
|
из мёртвых имён никто не бросает, переименование ничего не сдвигает (#72).
|
|
Заказная сторона уже названа — подпоток `ORDERS` ([судьба
|
|
заказа](fate.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).
|