Files
clickstream-ch-kafka-supers…/.scratch/backup/20260726-resolution-15.md
T
ddadminandClaude Fable 5 2e42cf63ff chore(scratch): сохранены слепок трекера и handoff миграции на Gitea
- Зачем:
  - 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>
2026-07-26 22:03:00 +03:00

100 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Ответ
Сумма заказа живёт **на обеих сторонах**, и стороны законно расходятся:
клиентское событие несёт объявленную сумму (то, что сайт продиктовал трекеру
через 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` (вероятность).
- Пятый эффект бесплатно даёт формат доставки: **опоздание** (заказ впервые
появляется в слепке 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).