From 05e4cdea4d8479c5ba4d1e44b2d80e8e5e40f4d7 Mon Sep 17 00:00:00 2001 From: Dmitry Dementiev Date: Thu, 30 Jul 2026 15:24:50 +0300 Subject: [PATCH] =?UTF-8?q?docs(specs):=20=D1=81=D0=BF=D0=B5=D0=BA=D0=B0?= =?UTF-8?q?=20=C2=AB=D0=91=D0=BE=D0=B5=D0=B2=D0=BE=D0=B9=20=D1=80=D0=B5?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=BC=20v2=C2=BB=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D0=BD=D1=8F=D1=82=D0=B0=20=D0=B2=D0=BB=D0=B0=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D1=86=D0=B5=D0=BC=20(#17)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Зачем: - зафиксировать вердикт владельца по трём помеченным отступлениям и закрыть приёмку спеки. - Что: - статус Draft -> Accepted; подтверждены порядок страховочных срезов и VisitID как эталон самопроверки. - Sign взят как колонка формата без механики (всегда 1, 47-я колонка события); честность — комментарий в DDL, абзац в документе о реализме, лекционный крючок про CollapsingMergeTree. - в опорные точки добавлена рамка лабы сессий: сначала собрать самому, потом рассказ про VisitID в хитах с октября 2025. - Проверка: - вычитка разделов 1.1, 1.2, 10, 12 и шапки статуса. Co-Authored-By: Claude Fable 5 --- docs/specs/2026-07-30-stand-v2-realism.md | 34 +++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/specs/2026-07-30-stand-v2-realism.md b/docs/specs/2026-07-30-stand-v2-realism.md index a992890..c1a7114 100644 --- a/docs/specs/2026-07-30-stand-v2-realism.md +++ b/docs/specs/2026-07-30-stand-v2-realism.md @@ -1,6 +1,8 @@ # Боевой реализм стенда (v2): широкое событие, заказы, кластер, анонимность -Статус: Draft — на приёмку владельцу. +Статус: Accepted (2026-07-30). Три помеченных отступления подтверждены +владельцем на приёмке: порядок страховочных срезов (раздел 9), `Sign` как +колонка без механики (раздел 1.1), `VisitID` как эталон самопроверки (1.2). Дата: 2026-07-30. Тикет: #17 (сборка карты #10). Источники: резолюции #18 (модель данных), #15 (`purchase` и заказы), #14 (кластер), #13 (цена кластера), #16 (анонимность и склейка); исследование @@ -64,10 +66,13 @@ JSON-поле `ecommerce`. Сессий в потоке нет — их мент тоже не берём, но это наш выбор, а не запрет источника: исследование запрещало только выдавать это поле за формат Яндекса, оставить разрешало. Разбор строки user agent — не урок этого стенда. -- **Механику версий записи (`Sign`/`HitVersion`) не берём сейчас**: по #15 это - кандидат на потом, и её дом — клиентская сторона (поток визитов Метрики - Про). Это помеченное отступление от рекомендации исследования («`Sign` на - хитах полезен»): колонка без механики — мёртвый вес. +- **`Sign` берём как колонку формата, без механики** (решение владельца на + приёмке спеки): генератор всегда пишет `Sign = 1`, исправлений записей не + шлёт — движки и запросы не меняются. Сама механика версий + (CollapsingMergeTree, пара `HitVersion`) — кандидат на потом, по #15. + Честность: комментарий в DDL и абзац в документе о реализме («в бою здесь + бывают −1/+1, считают через `sum(Sign)`»); в лекции — крючок про + CollapsingMergeTree (частый вопрос на собеседованиях). - **Не берём** `ClientEventTime` (в выгрузке Метрики нет клиентской метки; расхождение часов — тема тумана «грязь»), `Params` (второй сырой JSON не нужен: этот навык уже несут заказы), `LastSearchEngineRoot`, `IsPageView`, @@ -78,7 +83,7 @@ JSON-поле `ecommerce`. Сессий в потоке нет — их мент - **Наша честная добавка** — `EventType`: у Метрики такого поля нет (там `isPageView` + `productEventType`), стенду таксономия нужна явно. -### 1.2 Состав полей (46 колонок) +### 1.2 Состав полей (47 колонок) Идентификаторы и время: @@ -92,6 +97,7 @@ JSON-поле `ecommerce`. Сессий в потоке нет — их мент | `UTCEventTime` | DateTime | единственная метка времени, как у Метрики | | `ClientTimeZone` | Int16 | смещение пояса клиента в минутах | | `EventType` | LowCardinality(String) | `pageview` / `add_to_cart` / `purchase` | +| `Sign` | Int8 | всегда 1: колонка формата, механика исправлений не реализована (см. 1.1) | Правила резки визитов в генераторе документируются и совпадают с лабной логикой (30-минутный таймаут). @@ -155,7 +161,7 @@ Ecommerce (заполнены только у торговых событий): ### 1.4 Схема как контракт Одно машинное описание схемы события (python-модуль или YAML) — источник -истины: из него выводятся DDL и валидация генератора, а не наоборот. 46 +истины: из него выводятся DDL и валидация генератора, а не наоборот. 47 колонок повторяются примерно в семи местах (генератор, DDL, SELECT матвью, трансформации, витрины, манифест, доки) — без контракта они расходятся молча. Заодно это учебный артефакт: менти видит на живом примере, что такое @@ -295,7 +301,7 @@ CSV в репозитории (`data/catalog/products.csv`: `sku`, `name`, `cate прогонами, куда легли данные — нет». - **Приём строгий**: `input_format_skip_unknown_fields = 0`, обязательные поля — без значений по умолчанию. Контракт присутствия: генератор выдаёт - **все 46 полей в каждом событии**; «пусто» — пустой массив, пустая строка + **все 47 полей в каждом событии**; «пусто» — пустой массив, пустая строка или 0, а не отсутствие ключа в JSON. Так строгий приём уживается с полями, пустыми по смыслу (ecommerce у `pageview`, UTM у прямого захода). Несовпадение имени поля — громкая ошибка в `*_errors`, а не молчаливые нули: имена CamelCase регистрозависимы, @@ -501,8 +507,8 @@ smoke-проверки, а не «дашборд зелёный». Это мин - Реплики (2×2), HAProxy, репликационная эксплуатация — в лекцию, не в стенд. - Полный словарь торговых событий Метрики (detail, remove, impressions), пять уровней категорий, блоки `purchasedProduct*`/`impressions*`. -- `Sign`/CollapsingMergeTree — кандидат на потом (дом — поток визитов - Метрики Про). +- Механика `Sign`/CollapsingMergeTree — кандидат на потом (дом — поток + визитов Метрики Про); сама колонка `Sign` уже в схеме, статикой (см. 1.1). - Событийный лог заказов, CDC/Debezium, HTTP-сервис заказов, шапка+строки, отдельный поток возвратов — отклонены в #15/#18. - Файловые дропы как источник — зона следующего стенда (Lakehouse), у нас @@ -547,7 +553,8 @@ smoke-проверки, а не «дашборд зелёный». Это мин Logs API — это скачанный TSV»); trade-off «инкремент экономнее, слепок надёжнее» + сноска про compacted topic; identity stitching перестаёт быть чистой теорией; «прямое чтение прод-базы — анти-приём, в бою — реплика или -выгрузка»; полный словарь торговых событий — теория. +выгрузка»; колонка `Sign` без механики — честное ограничение стенда +(в бою −1/+1 и `sum(Sign)`); полный словарь торговых событий — теория. В v1 при заморозке — указатель на v2 в README (форму решить при рождении v2, этап 0). @@ -564,6 +571,11 @@ v2, этап 0). - сцена «разные consumer groups → дубли»; - словарь регионов из CSV той же машинерией, что каталог товаров (оживляет `RegionCityID`); +- лаба сессий: менти сначала собирает сессии сам, и только после — рассказ, + что с октября 2025 Метрика отдаёт `VisitID` прямо в хитах; частично + синтетическая постановка — осознанный приём; +- лекция «`Sign` и CollapsingMergeTree»: почему на стенде `sum(Sign)` = + `count()`, а в бою — нет; частый вопрос на собеседованиях; - лекция про идентичность «как в бою»: `setUserID` и first-party id, детерминированная против вероятностной склейки, identity graph, кросс-девайс, CDP — с рамкой «мы склеили через транзакции, потому что трекер