diff --git a/docs/specs/2026-07-30-stand-v2-realism.md b/docs/specs/2026-07-30-stand-v2-realism.md index 519383a..a992890 100644 --- a/docs/specs/2026-07-30-stand-v2-realism.md +++ b/docs/specs/2026-07-30-stand-v2-realism.md @@ -196,7 +196,9 @@ Ecommerce (заполнены только у торговых событий): Пропущенный день ничего не ломает, следующий слепок самовосстанавливает. - Разбор JSON-позиций — **один раз**, в трансформации ODS → DDS; дальше - витрины работают с плоскими массивами. Это единственный носитель навыка + витрины работают с плоскими массивами `dds.order`: `item_sku` + Array(String), `item_qty` Array(UInt64), `item_price` Array(Decimal(18,2)) + — одной длины, порядок как в JSON. Это единственный носитель навыка «вложенный JSON в ClickHouse» на стенде. - Статусы держим все три: смена `created` → `paid` и есть причина «дыхания» выручки внутри окна; сужение до двух — резервный срез 1. @@ -212,7 +214,10 @@ CSV в репозитории (`data/catalog/products.csv`: `sku`, `name`, `cate ## 4. Сверка `purchase` против заказов Ключ: клиентский `purchaseID` = `order_id` бэкенда (магазин знает номер -заказа на `/confirmation`). Расхождения — перечислимый список, +заказа на `/confirmation`). У события `purchase` массив `purchaseID` несёт +ровно один элемент (одно подтверждение — один заказ), сверка соединяет по +`purchaseID[1]`; правило зафиксировать комментарием в SQL сверки. +Расхождения — перечислимый список, детерминированный от seed, не хаос: | | Расхождение | Механика в генераторе | Ориентир доли | @@ -235,7 +240,10 @@ CSV в репозитории (`data/catalog/products.csv`: `sku`, `name`, `cate механически дублирует B. Правило стенда: **поведение и атрибуцию считаем по трекеру, деньги — по -бэкенду**. Оно выучивается на конфликте: суммы не сойдутся, менти сам +бэкенду**. Единственное разрешённое исключение — клиентская оценка выручки +под именем `declared_*` там, где атрибуция без трекера невозможна (UTM); +слово `declared` в имени — сигнал «это заявка клиента, не деньги +отчётности». Оно выучивается на конфликте: суммы не сойдутся, менти сам раскопает почему (Float64 против Decimal, промокод, доставка, отмены). ## 5. Анонимность и склейка идентичностей @@ -286,7 +294,10 @@ CSV в репозитории (`data/catalog/products.csv`: `sku`, `name`, `cate `cityHash64(сырой строки)`. Урок: «какая нода читала топик — меняется между прогонами, куда легли данные — нет». - **Приём строгий**: `input_format_skip_unknown_fields = 0`, обязательные - поля — без значений по умолчанию. Несовпадение имени поля — громкая + поля — без значений по умолчанию. Контракт присутствия: генератор выдаёт + **все 46 полей в каждом событии**; «пусто» — пустой массив, пустая строка + или 0, а не отсутствие ключа в JSON. Так строгий приём уживается с + полями, пустыми по смыслу (ecommerce у `pageview`, UTM у прямого захода). Несовпадение имени поля — громкая ошибка в `*_errors`, а не молчаливые нули: имена CamelCase регистрозависимы, опечатка иначе не падает. - **Политика соединений**: по ключу ко-локации — обычное соединение с @@ -370,8 +381,11 @@ Kafka переобработка возможна только из эталон в порядке приоритета — классы пересекаются, побеждает более ранний). `match` — большинство строк; `amount_delta` — только необъяснённый остаток после приведения к сравнимой базе (округления Float64, ~1–2% заказов). - Строка «`purchase` без заказа» внутри живого окна — это опоздание, ждущее - слепка, а не отдельный класс расхождения. + Строка «`purchase` без заказа» внутри живого окна — опоздание, ждущее + слепка, а не расхождение: она получает служебный класс `awaiting_order` + (шестое значение `mismatch_class`, вне приоритетов расхождений). После + закрытия окна K таких строк не остаётся — сироты исключены построением + (раздел 4). - **`v_utm_effectiveness`** — остаётся клиентской (атрибуция по трекеру); счётчики `purchases`/`add_to_carts` оживают из таксономии, добавляется `declared_revenue` по UTM. @@ -398,7 +412,7 @@ Kafka переобработка возможна только из эталон Манифест расширяется контрольными числами: - заказная сторона: заказы и выручка по дням; манифест хранит точные - счётчики по каждому классу расхождений (отмены, потери, дубли) — + счётчики по каждому классу расхождений (отмены, потери, дубли, дельты сумм) — самопроверка лабы сверки; - идентичность: uniq кук, uniq известных пользователей, число двухкуковых покупателей — лаба склейки получает самопроверку. @@ -469,7 +483,8 @@ v2 стартует пустым, поэтому объём ниже — это 9. Мониторинг и runbook «keeper упал / DDL повис в очереди». Критерий приёмки этапа — честный: `make up` работает и проходят -smoke-проверки, а не «дашборд зелёный». Документация правится в PR этапа +smoke-проверки, а не «дашборд зелёный». Это минимальная планка; свои +наблюдаемые критерии каждый этап получает при разбиении в /to-tickets. Документация правится в PR этапа (правило AGENTS.md). ## 10. Границы: чего не делаем