- Зачем:
- GitHub-аккаунт заблокирован 2026-07-26; трекер карты «боевой
реализм» перенесён на git.dementev.space, контекст нужен новой
сессии независимо от исхода апелляции.
- Что:
- .scratch/backup/ — слепок всех 27 issues и резолюция тикета #15
на момент блокировки;
- .scratch/handoffs/ — handoff с состоянием карты, нюансами доступа
к Gitea и списком хвостов (апелляция, выбор основного трекера).
- Проверка:
- тексты читаются; ссылки на Gitea-трекер открываются
(git.dementev.space/ddmitry/clickstream-ch-kafka-superset-demo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8.1 KiB
Ответ
Сумма заказа живёт на обеих сторонах, и стороны законно расходятся: клиентское событие несёт объявленную сумму (то, что сайт продиктовал трекеру через dataLayer — до пересчёта на бэкенде), заказ бэкенда — итоговую правду со статусами. Правило стенда: поведение и атрибуцию считаем по трекеру, деньги — по бэкенду. Правило выучивается на конфликте: суммы у менти не сойдутся, и он сам раскопает почему.
Клиентская сторона (широкое событие, рамка #18)
- Таксономия торговых событий:
pageview+add_to_cart+purchase. Полный словарь Метрики (detail,remove,impressions) не берём: механика та же, объём массивов большой, новых идей нет — остаётся теорией в документе о реализме. purchaseнесётpurchaseID/Revenue/Currency/Coupon+ массивыproduct*состава заказа + сырую строкуecommerce(по образцу выгрузки Метрики, фактура — #27).add_to_cart— массивыproduct*с одним товаром. Оживают мёртвые счётчикиpurchases/add_to_cartsвv_utm_effectivenessбез правки витрины.
Сторона бэкенда (второй источник, рамка #18)
- Формат выгрузки: полный ежедневный слепок заказов в пределах окна
изменяемости K дней. Запись = снапшот заказа:
order_id,user_id, времена,status(created/paid/cancelled),updated_at, итоговые суммы (товары / скидка / доставка / итого) + позиции вложенным JSON (items: [{sku, qty, price}]) — «родной» экспорт бэкенда, а не диалект Метрики. - Обоснование слепка (а не инкремента): очень частый боевой формат; идемпотентный приём и самовосстановление (пропущенный день ничего не ломает); дедуп до последней версии становится обязательным с первого дня. Окно K делает объём защитимым (за окном заказ неизменяем — возить незачем) и даёт границу пересчёта: выручка дня D «дышит» K дней, потом замерзает.
- Приём: дедуп через
ReplacingMergeTree/argMax; разбор JSON-позиций — один раз в трансформации ODS → DDS, дальше витрины работают с плоскими массивами. Это единственный носитель навыка «вложенный JSON в ClickHouse» в стенде. - В
docs/generator-realism.md— честный абзац trade-off «инкремент экономнее, слепок надёжнее» и сноска про compacted topic как родной Kafka-паттерн для состояния сущности.
Сверка
- Ключ: клиентский
purchaseID=order_idбэкенда (магазин знает номер заказа на/confirmation— какactionField.idу Метрики). - Конструируемые расхождения — перечислимый список из четырёх причин,
детерминированных от seed:
- A. Отмена —
purchaseесть, заказ дошёл доstatus='cancelled'(бесплатно из статусов); - B. Потерянное событие — заказ есть,
purchaseне доехал (вероятность в генераторе); - C. Дельта суммы — систематическая, по построению: клиент объявляет сумму товаров до промокода и доставки, бэкенд — итог; менти может вывести формулу связи;
- D. Дубль события — повторный
purchaseот обновления/confirmation(вероятность).
- A. Отмена —
- Пятый эффект бесплатно даёт формат доставки: опоздание (заказ впервые появляется в слепке D+1/D+2) — «вчера не сходилось, сегодня сошлось».
- Не берём: сироту-фрод (дублирует B механически) и расхождение часов клиент/сервер — это жители тумана «Грязь в данных», придут своим тикетом.
Слои и витрины
- DDS: одна новая сущность
dds.order(последняя версия заказа, позиции разобраны в массивы).purchaseотдельной сущности не получает — это строка широкого события. - DM, три роли: выручка (
v_revenue_daily, по категориям черезdictGetкаталога) — строится только от заказов; сверка (v_purchase_vs_orders) — FULL OUTER JOIN по ключу с классификатором расхождения; атрибуция (v_utm_effectiveness) — остаётся клиентской, плюс объявленная выручка по UTM. Точный состав колонок — в спеку (#17).
Эталонный мир
Пересборка артефакта неизбежна и уже оплачена решением #18; этот тикет нагружает её смыслом: манифест расширяется контрольными числами заказной стороны — заказы и выручка по дням, и ровно N потерянных / M дублей / K отмен для самопроверки лабы сверки. Политика версионирования артефакта здесь не решается (пункт тумана карты).
Ограничения исполнения и страховочные срезы
Аудитория — джун после базовой программы: расхождения — перечислимый список,
не хаос. Если при сборке спеки (#17) суммарный объём испугает, резать в
порядке: (1) статусы сузить до created/cancelled — урок дедупа держится
на самом слепке; (2) расхождения вводить поэтапно — сначала A+C, потом B+D;
(3) окно K сделать константой мира, а не параметром.
Отклонено по дороге
Событийный лог заказов (сборка автомата — дальше от типовой работы DE), CDC-формат (имитация Debezium без Debezium), шапка+строки (воскрешает склейку по ключам), отдельный поток возвратов, полный словарь торговых событий Метрики, механика Sign/CollapsingMergeTree (остаётся кандидатом на потом, её дом — клиентская сторона, поток визитов Метрики Про, не заказы).
Фактура: docs/research/2026-07-26-yandex-clickstream-format.md (#27),
резолюция «Модель данных» (#18).