Карта завершена, когда цельная спека второго источника — заказов бэкенда —
принята владельцем и лежит живым набором docs/architecture/orders/ в main, а этап 3 нарезан на
тикеты чек-листом в #5.
Карта несёт и исполнение маршрута, а не только решения по развилкам: /brainstorm-with-docs по развилкам (сначала веер, потом конвергенция) → /to-spec: спека файлом → приёмка владельцем → /to-tickets режет тикеты
этапа 3. Образец — карта #26, тем же порядком собрана спека генератора.
Заведена сразу после закрытия этапа 2, а не при входе в этап: пока карты нет,
второй источник живёт только разделами мастер-спеки и выглядит забытым. В коде
от него сегодня есть один каталог товаров — топик orders не создаётся, таблиц
заказа нет, генератор слепков не написан.
Заметки
Источник истины — мастер-спека docs/specs/2026-07-30-stand-v2-realism.md;
сначала читать разделы 2 (заказы), 3 (каталог), 4 (сверка), 5 (мост к
склейке), 7 (карта слоёв — там абзац про нерешённую развилку приёма) и
9 (страховочные срезы: что применено, что в резерве).
Ещё до начала прочитать: docs/adr/0005-event-ingestion.md — чем обоснован
приём для событий; docs/architecture/storage.md — служебные колонки,
конвенция суффиксов, сроки хранения; docs/specs/2026-08-01-generator.md —
детерминизм, иерархия зёрен, правило порядка бросков.
Развилки вести через /brainstorm-with-docs с /grilling и /domain-modeling; отклонённые варианты записывать с доводами.
Расхождение решения с мастер-спекой вносится в неё тем же коммитом, что и
спека второго источника.
Спорные API перед фиксацией сверять через MCP Context7 (правило AGENTS.md).
Вход извне карты: #63 — часовые пояса. Слепок несёт created_at, updated_at и snapshot_date; их семантика закреплена в формате. Устройство
модели DDS решается, когда начинаем строить DDS.
Решения по пути
Приём заказов: нужен ли слепку слой сырья
— пакетный забор: байтовый чтец без матвью, сырьё есть, в ods.order_snapshot
пишет шаг Airflow заменой партиции; топик в одну партицию, чтец на ноде 1 без ON CLUSTER. Раздел 12 переписан на «поток против слепка», сенсор снят, даг
переехал на этап 3. Целиком — docs/adr/0008-order-ingestion.md. Публикацию
через замену партиции позднее отменил «Брак в слепке: куда уходит и по каким
классам»:
прямое чтение не задаёт границы полного слепка, а ODS принимает версии заказа.
Генератор слепков: где живёт и чем связан с событиями
— заказ не порождается заново, а проецируется: торговая половина отдаёт заказы
дня структурой, ни одного нового броска в COMMERCE. Команда snapshot того же
пакета: два источника — два запуска. Окно K = 7 собирается переигровкой семи
дней; слепок снимается на границе суток, а отправляется следующим прогоном —
ночная выгрузка за вчера, отчего живой день перестаёт быть особым случаем.
Случайность — свой компонент дня по дню рождения заказа, вся судьба решается при
рождении; момент оплаты — бросок по таблице целых весов. Целиком — в резолюции
тикета.
Расхождения A–D и опоздания: механика, доли и что обещано
— расхождение это судьба заказа, решённая при рождении и уложенная в окно: два
подпотока (заказная сторона и порча событийного потока), броски независимы и
делаются на полную длину дня, приоритет мастер-спеки работает по-настоящему.
Заказ на выходе из окна либо paid, либо cancelled — неоплаченный отменяют,
«навсегда created» не возникает, нового значения mismatch_class не нужно.
Судьба бросается исходом из таблицы долей и моментами из таблицы длиной 143 часа
(самый узкий край окна); форма из #71 — вес за краем окна — этим отменена.
Дельта суммы — вычеркнутая позиция, заказ приезжает урезанным во всех слепках;
потеря точечная и не трогает назначенные планом покупки, а назначенные заказы
вдобавок не опаздывают — иначе рвётся лаба склейки с обоих концов; дубль
сюжетный и только там, где есть место до следующего визита куки;
опоздание кончается на втором-третьем дне. Опись считает наблюдаемые классы
после приоритета, единица счёта — заказ, и получает строку на слепок с хешем
байтов. Целиком — в резолюции тикета.
Мост к склейке: user_id и двухкуковые пары
— план владеет человеком и связью с куками: непрозрачный person_id
воспроизводится последним броском когорты, заказ показывает его как user_id,
а кликстрим остаётся анонимным; богатой модели аккаунта и отдельного реестра
нет. Целиком — в резолюции тикета.
Место заказов в стартовом мире
— стартовый мир отправляет семь слепков (дни 0…6): слепок дня 7 снят на
границе суток и уедет первым ходом мира, поэтому у последнего прожитого дня
клики есть, а заказов нет, и график выручки заваливается к правому краю,
дозаполняясь по ходу мира — главный наблюдаемый эффект ночной выгрузки.
Особого режима у стартового мира не заводится, генератору тикет не стоит
ничего. Опись держит правило «только то, чего движение мира не меняет»:
хеши дней и слепков плюс счётчики дней с закрытым окном (на стартовом мире
один); хеш — растяжка, счётчик — опора, и счётчик кладётся только с названным
читателем. Контрольные числа идентичности из мастер-спеки §5 и §8 не заводятся
вовсе. Опись описывает мир, а не доставку: работа генератора кончается на
Kafka. Целиком — в резолюции тикета.
Форма записи слепка на проводе
— деньги передаются строками с двумя знаками, items — обычным JSON-массивом; created_at и updated_at — аудит источника в UTC до миллисекунд, snapshot_date — дата модельного среза. Один внешний orjson.dumps, без
универсального слоя кодеков. Целиком — в резолюции тикета и docs/research/2026-08-16-order-snapshot-wire-format.md.
Брак в слепке: куда уходит и по каким классам
— строка либо целиком проходит строгий контракт 11 верхних полей, либо уходит
сырой в _errors с классом not_an_object, keyset_mismatch или field_invalid; два взаимодополняющих запроса читают один срез STG по _load_id. ODS принимает версии на ReplacingMergeTree(updated_at) по order_id; snapshot_date остаётся происхождением строки, точное текущее
чтение требует FINAL. Подмена партиций из «Приёма заказов: нужен ли слепку
слой сырья»
этим отменена. Итог закреплён в ADR 0010
и спецификации приёма
(после вычитания #84 живёт в наборе docs/architecture/orders/).
Собрать спеку заказов из решений развилок
— черновик цельной спеки второго источника лежит в docs/specs/2026-08-16-orders.md (коммит 905ca5b): решения #70–#74, #80, #81 в одной картине, расхождения с мастер-спекой, спекой генератора,
ADR 0008 и CONTEXT.md внесены тем же коммитом. Впереди вычитание #84 и
приёмка #88.
Вычитание: какая механика этапа 3 не окупает себя эффектом
— вычитание слилось с переустройством формы: спека заказов и спека приёма
превращены в живой набор docs/architecture/orders/ (индекс и девять файлов
по частям устройства), датированные файлы удалены, форма закреплена
ADR 0011. По итогам двух слепых холодных линий провод и приём сведены к
указателям (правило порядка строк слепка выжило на месте), замеры зерна и
повторы срезаны; списки отклонённых вариантов сохранены, машинерия
детерминизма не тронута — её пересмотр был бы переоткрытием #71–#74.
Холодная сверка миграции потерь не нашла. Целиком — в резолюции тикета.
Приёмка спеки заказов владельцем
— набор принят проводкой по всем файлам; резолюции развилок не открывались,
стык «сдвиг отправки ↔ семь слепков стартового мира» сошёлся. Единственная
правка приёмки — нарезка укрупнена с девяти файлов до семи (правило «семь
плюс-минус два»): projection влит в snapshot.md, mismatch — в fate.md, каждая
пара несла одну резолюцию. Черновой статус снят из README — набор живой и
правится по мере постройки (коммит cf1c6c4).
Нарезать тикеты этапа 3 по принятой спеке
— этап нарезан семью тикетами #90–#96 чек-листом в #5: генератор
(проекция → судьба → команда snapshot) → приём (топик и забор →
версионный ODS) → стартовый мир; словарь товаров параллельно. Приём живёт
отдельным дагом: работники пульта триггерят его, заливка make up дёргает
разово — путь один. Нарезка прошла холодное ревью; DDS заказа уехал
этапу 4 (коммит 5f72e63); #86 перевешен в чек-лист #5. Целиком — в
резолюции тикета.
Тикеты
Устройство второго источника живёт набором docs/architecture/orders/
(приём — orders/ingestion.md); набор принят владельцем (#88). Этап 3
нарезан (#89): тикеты #90–#96 чек-листом в #5, #86 перевешен туда же.
Блокировки — нативные зависимости Gitea, они же определяют фронтир. Если открыто несколько разблокированных и неназначенных тикетов, берётся первый по этому списку.
Нужен ли расхождениям собственный контур проверок данных и где он живёт:
даг DQ, витрина dm.dq_summary или обе.
За границей карты
Решённое мастер-спекой заново не обсуждается: поля слепка, окно K = 7 как
константа мира, три статуса, приоритет классов расхождений, правило
«поведение и атрибуцию считаем по трекеру, деньги — по бэкенду».
Витрины и сама сверка purchase против заказов — этап 4 (#6).
Расхождения B и D как отдельный этап сверки — этап 6 (#8). Механику
генератора для них решаем здесь, сверку по ним пишут там.
## Пункт назначения
Карта завершена, когда цельная спека второго источника — заказов бэкенда —
принята владельцем и лежит живым набором `docs/architecture/orders/` в main, а этап 3 нарезан на
тикеты чек-листом в #5.
Карта несёт и исполнение маршрута, а не только решения по развилкам:
`/brainstorm-with-docs` по развилкам (сначала веер, потом конвергенция) →
`/to-spec`: спека файлом → приёмка владельцем → `/to-tickets` режет тикеты
этапа 3. Образец — карта #26, тем же порядком собрана спека генератора.
Заведена сразу после закрытия этапа 2, а не при входе в этап: пока карты нет,
второй источник живёт только разделами мастер-спеки и выглядит забытым. В коде
от него сегодня есть один каталог товаров — топик `orders` не создаётся, таблиц
заказа нет, генератор слепков не написан.
## Заметки
- Источник истины — мастер-спека `docs/specs/2026-07-30-stand-v2-realism.md`;
сначала читать разделы 2 (заказы), 3 (каталог), 4 (сверка), 5 (мост к
склейке), 7 (карта слоёв — там абзац про нерешённую развилку приёма) и
9 (страховочные срезы: что применено, что в резерве).
- Ещё до начала прочитать: `docs/adr/0005-event-ingestion.md` — чем обоснован
приём для событий; `docs/architecture/storage.md` — служебные колонки,
конвенция суффиксов, сроки хранения; `docs/specs/2026-08-01-generator.md` —
детерминизм, иерархия зёрен, правило порядка бросков.
- Развилки вести через `/brainstorm-with-docs` с `/grilling` и
`/domain-modeling`; отклонённые варианты записывать с доводами.
- Расхождение решения с мастер-спекой вносится в неё тем же коммитом, что и
спека второго источника.
- Спорные API перед фиксацией сверять через MCP Context7 (правило AGENTS.md).
- Вход извне карты: #63 — часовые пояса. Слепок несёт `created_at`,
`updated_at` и `snapshot_date`; их семантика закреплена в формате. Устройство
модели DDS решается, когда начинаем строить DDS.
## Решения по пути
<!-- по одной строке на закрытый тикет: суть ответа и ссылка -->
- [Приём заказов: нужен ли слепку слой сырья](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/70)
— пакетный забор: байтовый чтец без матвью, сырьё есть, в `ods.order_snapshot`
пишет шаг Airflow заменой партиции; топик в одну партицию, чтец на ноде 1 без
`ON CLUSTER`. Раздел 12 переписан на «поток против слепка», сенсор снят, даг
переехал на этап 3. Целиком — `docs/adr/0008-order-ingestion.md`. Публикацию
через замену партиции позднее отменил [«Брак в слепке: куда уходит и по каким
классам»](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/80):
прямое чтение не задаёт границы полного слепка, а ODS принимает версии заказа.
- [Генератор слепков: где живёт и чем связан с событиями](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/71)
— заказ не порождается заново, а проецируется: торговая половина отдаёт заказы
дня структурой, ни одного нового броска в `COMMERCE`. Команда `snapshot` того же
пакета: два источника — два запуска. Окно K = 7 собирается переигровкой семи
дней; слепок снимается на границе суток, а отправляется следующим прогоном —
ночная выгрузка за вчера, отчего живой день перестаёт быть особым случаем.
Случайность — свой компонент дня по дню рождения заказа, вся судьба решается при
рождении; момент оплаты — бросок по таблице целых весов. Целиком — в резолюции
тикета.
- [Расхождения A–D и опоздания: механика, доли и что обещано](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/72)
— расхождение это судьба заказа, решённая при рождении и уложенная в окно: два
подпотока (заказная сторона и порча событийного потока), броски независимы и
делаются на полную длину дня, приоритет мастер-спеки работает по-настоящему.
Заказ на выходе из окна либо `paid`, либо `cancelled` — неоплаченный отменяют,
«навсегда `created`» не возникает, нового значения `mismatch_class` не нужно.
Судьба бросается исходом из таблицы долей и моментами из таблицы длиной 143 часа
(самый узкий край окна); форма из #71 — вес за краем окна — этим отменена.
Дельта суммы — вычеркнутая позиция, заказ приезжает урезанным во всех слепках;
потеря точечная и не трогает назначенные планом покупки, а назначенные заказы
вдобавок не опаздывают — иначе рвётся лаба склейки с обоих концов; дубль
сюжетный и только там, где есть место до следующего визита куки;
опоздание кончается на втором-третьем дне. Опись считает наблюдаемые классы
после приоритета, единица счёта — заказ, и получает строку на слепок с хешем
байтов. Целиком — в резолюции тикета.
- [Мост к склейке: user_id и двухкуковые пары](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/73)
— план владеет человеком и связью с куками: непрозрачный `person_id`
воспроизводится последним броском когорты, заказ показывает его как `user_id`,
а кликстрим остаётся анонимным; богатой модели аккаунта и отдельного реестра
нет. Целиком — в резолюции тикета.
- [Место заказов в стартовом мире](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/74)
— стартовый мир отправляет семь слепков (дни 0…6): слепок дня 7 снят на
границе суток и уедет первым ходом мира, поэтому у последнего прожитого дня
клики есть, а заказов нет, и график выручки заваливается к правому краю,
дозаполняясь по ходу мира — главный наблюдаемый эффект ночной выгрузки.
Особого режима у стартового мира не заводится, генератору тикет не стоит
ничего. Опись держит правило «только то, чего движение мира не меняет»:
хеши дней и слепков плюс счётчики дней с закрытым окном (на стартовом мире
один); хеш — растяжка, счётчик — опора, и счётчик кладётся только с названным
читателем. Контрольные числа идентичности из мастер-спеки §5 и §8 не заводятся
вовсе. Опись описывает мир, а не доставку: работа генератора кончается на
Kafka. Целиком — в резолюции тикета.
- [Форма записи слепка на проводе](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/81)
— деньги передаются строками с двумя знаками, `items` — обычным JSON-массивом;
`created_at` и `updated_at` — аудит источника в UTC до миллисекунд,
`snapshot_date` — дата модельного среза. Один внешний `orjson.dumps`, без
универсального слоя кодеков. Целиком — в резолюции тикета и
`docs/research/2026-08-16-order-snapshot-wire-format.md`.
- [Брак в слепке: куда уходит и по каким классам](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/80)
— строка либо целиком проходит строгий контракт 11 верхних полей, либо уходит
сырой в `_errors` с классом `not_an_object`, `keyset_mismatch` или
`field_invalid`; два взаимодополняющих запроса читают один срез STG по
`_load_id`. ODS принимает версии на `ReplacingMergeTree(updated_at)` по
`order_id`; `snapshot_date` остаётся происхождением строки, точное текущее
чтение требует `FINAL`. Подмена партиций из [«Приёма заказов: нужен ли слепку
слой сырья»](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/70)
этим отменена. Итог закреплён в [ADR 0010](https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/adr/0010-order-versions-in-ods.md)
и [спецификации приёма](https://git.dementev.space/ddmitry/clickstream-data-platform/src/branch/main/docs/architecture/orders/ingestion.md)
(после вычитания #84 живёт в наборе `docs/architecture/orders/`).
- [Собрать спеку заказов из решений развилок](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/87)
— черновик цельной спеки второго источника лежит в
`docs/specs/2026-08-16-orders.md` (коммит 905ca5b): решения #70–#74, #80,
#81 в одной картине, расхождения с мастер-спекой, спекой генератора,
ADR 0008 и CONTEXT.md внесены тем же коммитом. Впереди вычитание #84 и
приёмка #88.
- [Вычитание: какая механика этапа 3 не окупает себя эффектом](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/84)
— вычитание слилось с переустройством формы: спека заказов и спека приёма
превращены в живой набор `docs/architecture/orders/` (индекс и девять файлов
по частям устройства), датированные файлы удалены, форма закреплена
ADR 0011. По итогам двух слепых холодных линий провод и приём сведены к
указателям (правило порядка строк слепка выжило на месте), замеры зерна и
повторы срезаны; списки отклонённых вариантов сохранены, машинерия
детерминизма не тронута — её пересмотр был бы переоткрытием #71–#74.
Холодная сверка миграции потерь не нашла. Целиком — в резолюции тикета.
- [Приёмка спеки заказов владельцем](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/88)
— набор принят проводкой по всем файлам; резолюции развилок не открывались,
стык «сдвиг отправки ↔ семь слепков стартового мира» сошёлся. Единственная
правка приёмки — нарезка укрупнена с девяти файлов до семи (правило «семь
плюс-минус два»): projection влит в snapshot.md, mismatch — в fate.md, каждая
пара несла одну резолюцию. Черновой статус снят из README — набор живой и
правится по мере постройки (коммит cf1c6c4).
- [Нарезать тикеты этапа 3 по принятой спеке](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/89)
— этап нарезан семью тикетами #90–#96 чек-листом в #5: генератор
(проекция → судьба → команда `snapshot`) → приём (топик и забор →
версионный ODS) → стартовый мир; словарь товаров параллельно. Приём живёт
отдельным дагом: работники пульта триггерят его, заливка `make up` дёргает
разово — путь один. Нарезка прошла холодное ревью; DDS заказа уехал
этапу 4 (коммит 5f72e63); #86 перевешен в чек-лист #5. Целиком — в
резолюции тикета.
## Тикеты
Устройство второго источника живёт набором `docs/architecture/orders/`
(приём — `orders/ingestion.md`); набор принят владельцем (#88). Этап 3
нарезан (#89): тикеты #90–#96 чек-листом в #5, #86 перевешен туда же.
Блокировки — нативные зависимости Gitea, они же определяют фронтир. Если открыто несколько разблокированных и неназначенных тикетов, берётся первый по этому списку.
- [x] #70 Приём заказов: нужен ли слепку слой сырья
- [x] #71 Генератор слепков: где живёт и чем связан с событиями
- [x] #72 Расхождения A–D и опоздания: механика, доли и что обещано
- [x] #73 Мост к склейке: user_id и двухкуковые пары
- [x] #74 Место заказов в стартовом мире
- [x] #81 Форма записи слепка на проводе
- [x] #80 Брак в слепке: куда уходит и по каким классам
- [x] #87 Собрать спеку заказов из решений развилок
- [x] #84 Вычитание: какая механика этапа 3 не окупает себя эффектом
- [x] #88 Приёмка спеки заказов владельцем
- [x] #89 Нарезать тикеты этапа 3 по принятой спеке
## Ещё не сформулировано
- Нужен ли расхождениям собственный контур проверок данных и где он живёт:
даг DQ, витрина `dm.dq_summary` или обе.
## За границей карты
- **Решённое мастер-спекой заново не обсуждается**: поля слепка, окно K = 7 как
константа мира, три статуса, приоритет классов расхождений, правило
«поведение и атрибуцию считаем по трекеру, деньги — по бэкенду».
- Витрины и сама сверка `purchase` против заказов — этап 4 (#6).
- Расхождения B и D как отдельный этап сверки — этап 6 (#8). Механику
генератора для них решаем здесь, сверку по ним пишут там.
- Пересборка эталонного мира целиком — этап 7 (#9).
- Код: пишется тикетами, нарезанными после приёмки спеки.
- Перевод мастер-спеки и спеки генератора в ту же живую форму — отдельное
усилие вне этой карты (ADR 0011).
- [Трассировка загрузки: нужен ли `_load_id` выше ODS](https://git.dementev.space/ddmitry/clickstream-data-platform/issues/85) — читатель колонки появится при проектировании `dds.order`, а это этап 4; тикет остаётся открытым и подвешен к #6.
Пункт назначения достигнут: набор docs/architecture/orders/ принят владельцем (#88), этап 3 нарезан тикетами #90–#96 чек-листом в #5 (#89). Открытых детей не осталось: #85 выведен за границу карты (этап 4), #86 перевешен в чек-лист #5. Оставшийся туман — контур проверок данных для расхождений — записан в orders/README.md, «Открытые решения», с местом разговора на этапе 4.
Пункт назначения достигнут: набор `docs/architecture/orders/` принят владельцем (#88), этап 3 нарезан тикетами #90–#96 чек-листом в #5 (#89). Открытых детей не осталось: #85 выведен за границу карты (этап 4), #86 перевешен в чек-лист #5. Оставшийся туман — контур проверок данных для расхождений — записан в `orders/README.md`, «Открытые решения», с местом разговора на этапе 4.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Пункт назначения
Карта завершена, когда цельная спека второго источника — заказов бэкенда —
принята владельцем и лежит живым набором
docs/architecture/orders/в main, а этап 3 нарезан натикеты чек-листом в #5.
Карта несёт и исполнение маршрута, а не только решения по развилкам:
/brainstorm-with-docsпо развилкам (сначала веер, потом конвергенция) →/to-spec: спека файлом → приёмка владельцем →/to-ticketsрежет тикетыэтапа 3. Образец — карта #26, тем же порядком собрана спека генератора.
Заведена сразу после закрытия этапа 2, а не при входе в этап: пока карты нет,
второй источник живёт только разделами мастер-спеки и выглядит забытым. В коде
от него сегодня есть один каталог товаров — топик
ordersне создаётся, таблицзаказа нет, генератор слепков не написан.
Заметки
docs/specs/2026-07-30-stand-v2-realism.md;сначала читать разделы 2 (заказы), 3 (каталог), 4 (сверка), 5 (мост к
склейке), 7 (карта слоёв — там абзац про нерешённую развилку приёма) и
9 (страховочные срезы: что применено, что в резерве).
docs/adr/0005-event-ingestion.md— чем обоснованприём для событий;
docs/architecture/storage.md— служебные колонки,конвенция суффиксов, сроки хранения;
docs/specs/2026-08-01-generator.md—детерминизм, иерархия зёрен, правило порядка бросков.
/brainstorm-with-docsс/grillingи/domain-modeling; отклонённые варианты записывать с доводами.спека второго источника.
created_at,updated_atиsnapshot_date; их семантика закреплена в формате. Устройствомодели DDS решается, когда начинаем строить DDS.
Решения по пути
Приём заказов: нужен ли слепку слой сырья
— пакетный забор: байтовый чтец без матвью, сырьё есть, в
ods.order_snapshotпишет шаг Airflow заменой партиции; топик в одну партицию, чтец на ноде 1 без
ON CLUSTER. Раздел 12 переписан на «поток против слепка», сенсор снят, дагпереехал на этап 3. Целиком —
docs/adr/0008-order-ingestion.md. Публикациючерез замену партиции позднее отменил «Брак в слепке: куда уходит и по каким
классам»:
прямое чтение не задаёт границы полного слепка, а ODS принимает версии заказа.
Генератор слепков: где живёт и чем связан с событиями
— заказ не порождается заново, а проецируется: торговая половина отдаёт заказы
дня структурой, ни одного нового броска в
COMMERCE. Командаsnapshotтого жепакета: два источника — два запуска. Окно K = 7 собирается переигровкой семи
дней; слепок снимается на границе суток, а отправляется следующим прогоном —
ночная выгрузка за вчера, отчего живой день перестаёт быть особым случаем.
Случайность — свой компонент дня по дню рождения заказа, вся судьба решается при
рождении; момент оплаты — бросок по таблице целых весов. Целиком — в резолюции
тикета.
Расхождения A–D и опоздания: механика, доли и что обещано
— расхождение это судьба заказа, решённая при рождении и уложенная в окно: два
подпотока (заказная сторона и порча событийного потока), броски независимы и
делаются на полную длину дня, приоритет мастер-спеки работает по-настоящему.
Заказ на выходе из окна либо
paid, либоcancelled— неоплаченный отменяют,«навсегда
created» не возникает, нового значенияmismatch_classне нужно.Судьба бросается исходом из таблицы долей и моментами из таблицы длиной 143 часа
(самый узкий край окна); форма из #71 — вес за краем окна — этим отменена.
Дельта суммы — вычеркнутая позиция, заказ приезжает урезанным во всех слепках;
потеря точечная и не трогает назначенные планом покупки, а назначенные заказы
вдобавок не опаздывают — иначе рвётся лаба склейки с обоих концов; дубль
сюжетный и только там, где есть место до следующего визита куки;
опоздание кончается на втором-третьем дне. Опись считает наблюдаемые классы
после приоритета, единица счёта — заказ, и получает строку на слепок с хешем
байтов. Целиком — в резолюции тикета.
Мост к склейке: user_id и двухкуковые пары
— план владеет человеком и связью с куками: непрозрачный
person_idвоспроизводится последним броском когорты, заказ показывает его как
user_id,а кликстрим остаётся анонимным; богатой модели аккаунта и отдельного реестра
нет. Целиком — в резолюции тикета.
Место заказов в стартовом мире
— стартовый мир отправляет семь слепков (дни 0…6): слепок дня 7 снят на
границе суток и уедет первым ходом мира, поэтому у последнего прожитого дня
клики есть, а заказов нет, и график выручки заваливается к правому краю,
дозаполняясь по ходу мира — главный наблюдаемый эффект ночной выгрузки.
Особого режима у стартового мира не заводится, генератору тикет не стоит
ничего. Опись держит правило «только то, чего движение мира не меняет»:
хеши дней и слепков плюс счётчики дней с закрытым окном (на стартовом мире
один); хеш — растяжка, счётчик — опора, и счётчик кладётся только с названным
читателем. Контрольные числа идентичности из мастер-спеки §5 и §8 не заводятся
вовсе. Опись описывает мир, а не доставку: работа генератора кончается на
Kafka. Целиком — в резолюции тикета.
Форма записи слепка на проводе
— деньги передаются строками с двумя знаками,
items— обычным JSON-массивом;created_atиupdated_at— аудит источника в UTC до миллисекунд,snapshot_date— дата модельного среза. Один внешнийorjson.dumps, безуниверсального слоя кодеков. Целиком — в резолюции тикета и
docs/research/2026-08-16-order-snapshot-wire-format.md.Брак в слепке: куда уходит и по каким классам
— строка либо целиком проходит строгий контракт 11 верхних полей, либо уходит
сырой в
_errorsс классомnot_an_object,keyset_mismatchилиfield_invalid; два взаимодополняющих запроса читают один срез STG по_load_id. ODS принимает версии наReplacingMergeTree(updated_at)поorder_id;snapshot_dateостаётся происхождением строки, точное текущеечтение требует
FINAL. Подмена партиций из «Приёма заказов: нужен ли слепкуслой сырья»
этим отменена. Итог закреплён в ADR 0010
и спецификации приёма
(после вычитания #84 живёт в наборе
docs/architecture/orders/).Собрать спеку заказов из решений развилок
— черновик цельной спеки второго источника лежит в
docs/specs/2026-08-16-orders.md(коммит905ca5b): решения #70–#74, #80,#81 в одной картине, расхождения с мастер-спекой, спекой генератора,
ADR 0008 и CONTEXT.md внесены тем же коммитом. Впереди вычитание #84 и
приёмка #88.
Вычитание: какая механика этапа 3 не окупает себя эффектом
— вычитание слилось с переустройством формы: спека заказов и спека приёма
превращены в живой набор
docs/architecture/orders/(индекс и девять файловпо частям устройства), датированные файлы удалены, форма закреплена
ADR 0011. По итогам двух слепых холодных линий провод и приём сведены к
указателям (правило порядка строк слепка выжило на месте), замеры зерна и
повторы срезаны; списки отклонённых вариантов сохранены, машинерия
детерминизма не тронута — её пересмотр был бы переоткрытием #71–#74.
Холодная сверка миграции потерь не нашла. Целиком — в резолюции тикета.
Приёмка спеки заказов владельцем
— набор принят проводкой по всем файлам; резолюции развилок не открывались,
стык «сдвиг отправки ↔ семь слепков стартового мира» сошёлся. Единственная
правка приёмки — нарезка укрупнена с девяти файлов до семи (правило «семь
плюс-минус два»): projection влит в snapshot.md, mismatch — в fate.md, каждая
пара несла одну резолюцию. Черновой статус снят из README — набор живой и
правится по мере постройки (коммит
cf1c6c4).Нарезать тикеты этапа 3 по принятой спеке
— этап нарезан семью тикетами #90–#96 чек-листом в #5: генератор
(проекция → судьба → команда
snapshot) → приём (топик и забор →версионный ODS) → стартовый мир; словарь товаров параллельно. Приём живёт
отдельным дагом: работники пульта триггерят его, заливка
make upдёргаетразово — путь один. Нарезка прошла холодное ревью; DDS заказа уехал
этапу 4 (коммит
5f72e63); #86 перевешен в чек-лист #5. Целиком — врезолюции тикета.
Тикеты
Устройство второго источника живёт набором
docs/architecture/orders/(приём —
orders/ingestion.md); набор принят владельцем (#88). Этап 3нарезан (#89): тикеты #90–#96 чек-листом в #5, #86 перевешен туда же.
Блокировки — нативные зависимости Gitea, они же определяют фронтир. Если открыто несколько разблокированных и неназначенных тикетов, берётся первый по этому списку.
Ещё не сформулировано
даг DQ, витрина
dm.dq_summaryили обе.За границей карты
константа мира, три статуса, приоритет классов расхождений, правило
«поведение и атрибуцию считаем по трекеру, деньги — по бэкенду».
purchaseпротив заказов — этап 4 (#6).генератора для них решаем здесь, сверку по ним пишут там.
усилие вне этой карты (ADR 0011).
_load_idвыше ODS — читатель колонки появится при проектированииdds.order, а это этап 4; тикет остаётся открытым и подвешен к #6.ddmitry referenced this issue2026-08-17 22:17:29 +03:00
Пункт назначения достигнут: набор
docs/architecture/orders/принят владельцем (#88), этап 3 нарезан тикетами #90–#96 чек-листом в #5 (#89). Открытых детей не осталось: #85 выведен за границу карты (этап 4), #86 перевешен в чек-лист #5. Оставшийся туман — контур проверок данных для расхождений — записан вorders/README.md, «Открытые решения», с местом разговора на этапе 4.