feat(ods): версией заказа стала дата слепка, окно DDS — из данных

- Зачем:
  - ярлык 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>
This commit is contained in:
ddadminandClaude Opus 5 committed 2026-08-26 17:28:14 +03:00
1 parent 650efacc3f
commit a82c75705d
13 files changed
+140 -141

No files matched your search

+10 -11
View File
@@ -66,15 +66,14 @@ ODS: это единственный устойчивый ключ сущнос
собран этот день».
Ярлыки ODS — `snapshot_date`, `_load_id` приёма, `_load_ts` прибытия — в
модель не переезжают. Версию заказа они не задают, а физически выжившие их
значения — жребий: у строк с равным `updated_at` деловые поля совпадают
побайтово, и какая переживёт схлопывание — произвол (замер —
[приём заказов](../orders/ingestion.md), «Что проверено»). Перенесённый
ярлык выглядел бы фактом, оставаясь жребием; лживая координата хуже
отсутствующей. Отсюда правило слоя: **служебные колонки — координаты
собственной загрузки слоя; чужие координаты спрашиваются у их слоя по ключу
сущности**. Этим закрыто наследство #85: читатель у чужих ярлыков выше ODS
не нашёлся и при названных читателях модели.
модель не переезжают. Лгать они перестали: колонкой версии в ODS стала дата
слепка, и у выжившей строки она равна последнему слепку, в котором заказ был
([ADR 0014](../../adr/0014-order-version-snapshot-date.md)). Довод стал проще:
читателя у этих колонок здесь нет — модель отвечает на вопрос «что сейчас
известно о заказе», а не «когда его показывал источник». Отсюда правило слоя:
**служебные колонки — координаты собственной загрузки слоя; чужие координаты
спрашиваются у их слоя по ключу сущности**. Этим закрыто наследство #85:
читатель у чужих ярлыков выше ODS не нашёлся и при названных читателях модели.
Происшествие качества данных расследуется цепочкой, где каждый шаг
спрашивает свой слой на его языке: по `_load_id` строки DDS видно, какой
@@ -109,8 +108,8 @@ ODS: это единственный устойчивый ключ сущнос
позиций и пересчёт времён при каждом чтении собирали бы модель заново на
лету. Публичное `dds.order_v` поверх готовой физической модели этому доводу
не противоречит: оно ничего заново не вычисляет.
- **`ReplacingMergeTree(updated_at)` ещё раз.** Повторил бы механику ODS
вторым разом: физически хранил бы устаревшие состояния, вернул бы `FINAL`
- **`ReplacingMergeTree` ещё раз.** Повторил бы механику ODS вторым разом:
физически хранил бы устаревшие состояния, вернул бы `FINAL`
и обёртку-представление — а урок версий менти уже отыграл.
- **Отдельная сущность `dds.order_item`.** Вторая таблица, второй вопрос
шардирования и `JOIN` там, где хватает `ARRAY JOIN`; нормализация из