Ресёрч: A/B-split нода и цели/конверсии в сценариях у конкурентов (MLF-296, шаг 1)

Задача: MLF-296 — «Сценарии: A/B-split нода + цели/конверсии (exit-on-goal) с атрибуцией на ветку». Это шаг 1 карточки (ресёрч), его результат ложится в шаг 2 (макеты ноды сплита RANDOMIZER и конфигуратора цели GOAL) и согласование с М. Терентьевым.

Дата: 2026-07-16 Метод: deep-research harness (5 углов → ~90 источников → извлечение фактов → 3-голосовая adversarial-верификация, 25 ключевых утверждений подтверждено). Финальный форматтер харнесса упал на structured-output — синтез собран вручную из верифицированного журнала. Скоуп: только то, что нужно для двух нод — (1) RANDOMIZER (проценты по веткам, семантика распределения, фиксация/стикинг при повторном входе, выбор победителя); (2) GOAL (целевое событие, окно атрибуции, exit-on-goal, атрибуция достижения на ветку и конверсия по веткам). Каналы, триггеры, инспекторы прочих нод — вне ресёрча (см. соседние RESEARCH-*.md).

Достоверность. Разделы Customer.io / Braze / Segment / Klaviyo основаны на first-party документации вендоров, каждый факт прошёл верификацию (в тексте помечены подтверждено). Раздел Mindbox — по одной странице офиц. доков (help.mindbox.ru/docs/workflow-ab-tests), подтверждён фетчем и поиском, но узкий. HubSpot и Iterable в вопрос входили, но релевантных первичных фактов харнесс не вернул — считаем непокрытыми (см. §9).


1. TL;DR — что берём в макеты RANDOMIZER и GOAL

  1. Random-split — отдельная нода с процентами по N веткам; сумма всегда 100%. У всех вендоров, где сплит есть как отдельная сущность (Customer.io «Random Cohort» — до 20 веток; Segment «Randomized Split» — до 5 веток), автор задаёт проценты вручную, и продукт не даёт сохранить/опубликовать, пока сумма ≠ 100%. Это прямой референс для нашей AutomationRandomizerNode (N динамических выходов с процентами, ADR-700 §…).

  2. Распределение — статистическое, не точное. Каждый контакт раскидывается независимо и случайно; «50/50» даёт примерно, а не ровно поровну (явно оговорено у Klaviyo и выводится из Braze bucket-модели). В UI цель не «ровно N человек в ветку», а «доля».

  3. Фиксация распределения при повторном входе — ключевая развилка, вендоры расходятся (§7.1). Три модели: (а) всегда стики — Mindbox (та же ветка при каждом повторном срабатывании); (б) стики условно — Segment v1 (та же ветка, только если у journey есть re-entry condition); (в) опция, по умолчанию ре-рандомизация — Segment v2 (тумблер «Assign same branch»). Customer.io добавляет 4-ю ось — стикинг на уровне объекта/когорты (все из одной компании идут одной веткой). Для нашей задачи («фиксация распределения контактов») нужно осознанно выбрать модель.

  4. Цель = целевое событие + окно атрибуции; exit-on-goal — ОТДЕЛЬНАЯ настройка, а не автоматика. Каноничный пример — Customer.io: достижение цели по умолчанию НЕ выводит из сценария; чтобы выводило, критерий цели нужно продублировать в exit conditions. У нас это уже заложено как флаг stopFlow на GOAL-ноде (ADR-500 §11) — ресёрч подтверждает, что exit-on-goal должен быть явным переключателем, а не поведением по умолчанию.

  5. Окно атрибуции (conversion/attribution window) — обязательный параметр цели. Customer.io: настраиваемое, до 90 дней. Klaviyo: пер-канальные дефолты (email 5 дней, SMS-клик 5 дней / open 1 день, push 24 ч, WhatsApp 5 дней / 12 ч), кастомизация до 90 дней, окно стартует в момент отправки сообщения. Braze: рекомендует окно не меньше самой длинной ветки Canvas; фактически тянется на 3 дня сверх макс. длительности, минимум — 5 минут. У нашей GOAL-ноды окна атрибуции сейчас НЕТ — это пробел, который закрывает MLF-296.

  6. Выбор победителя A/B — стат-значимость, а не «просто больше конверсий». Braze: Pearson chi-squared, ярлык «Winner» при p < 0.05 (95%); есть fallback «отправить лучший вариант всё равно», если порог не достигнут. Для MVP это, скорее всего, за рамками (у нас нет авто-winner), но важно как ориентир для будущей аналитики по веткам.

  7. Атрибуция достижения цели именно на A/B-ветку — слабо задокументирована у всех. Явных механик «конверсия по конкретной ветке сплита» первичные доки почти не раскрывают (Customer.io лишь декларирует цель — «видеть, какая ветка даёт больше конверсий»). Это наш дифференциатор и одновременно открытый вопрос (§8): контракт мы, вероятно, проектируем сами, а не копируем.


2. Customer.io (подтверждено)

Терминология: Random Cohort / Branch / Cohort by / Goal / conversion window / exit conditions.

2.1 Три типа ветвления — Random Cohort как A/B-механизм

Customer.io разделяет три типа flow-control нод:

2.2 Конфиг Random Cohort — прямой референс для нашей ноды

2.3 Стикинг ветки — на уровне когорты

"When someone reaches a random cohort block, we check their cohort. If the cohort has already been assigned to a branch, they'll go down that branch… future members of the same cohort will follow the same path." Т.е. повторный вход → та же ветка (стикинг per-cohort). Для Profile-когорты это де-факто per-person стикинг. → Референс для нашей «фиксации распределения».

2.4 Цели и конверсии


3. Braze (подтверждено)

Терминология: Canvas / random bucket number / exit event / conversion window / multivariate test / Winner.

3.1 Random-split — через persistent bucket numbers, не отдельной нодой

У Braze нет «процентной split-ноды» как в Customer.io; механика иная:

3.2 Выбор победителя (multivariate) — стат-значимость

3.3 Цели, окно атрибуции и exit — важно для GOAL


4. Segment / Twilio Engage — Journeys (подтверждено)

Терминология: Randomized Split / branch / re-entry condition / Assign same branch.

4.1 Randomized Split — проценты вручную

"Each branch receives a portion of the eligible users based on percentages that you assign to the branches." До 5 веток, процент на каждую; нельзя сохранить/опубликовать, пока сумма ≠ 100% и пока есть пустые. Назначение — случайное, по заданным долям. Источник: v1/step-types.

4.2 Стикинг — разный в v1 и v2 (ключ для §7.1)


5. Klaviyo (подтверждено)

Терминология: conditional split / Random sample / YES-path / attribution window.

5.1 A/B-split — НЕ отдельная нода, а conditional split с условием «Random sample»

5.2 Окно атрибуции — пер-канальное (референс для GOAL)

Дефолты (last-touch, окно стартует в момент отправки сообщения; кастомизируется до 90 дней):

Канал / событие Окно
Email клики / открытия 5 дней
SMS клики 5 дней
SMS открытия 1 день
Push открытия 24 часа
WhatsApp клики 5 дней
WhatsApp открытия 12 часов

Конверсия (напр. placed order) атрибутируется сообщению, только если событие попало в открытое окно этого сообщения. Источники: message attribution, Klaviyo Academy — attribution.


6. Mindbox (по одной странице офиц. доков — узко)

A/B-тест в сценарии — стикинг по контакту:

«Если клиент попал в сценарий и был отнесён к одной из веток АБ-теста, то при повторном попадании в этот сценарий с АБ-тестом клиент будет отнесён к той же ветке. Если сценарий может отрабатывать несколько раз на клиенте, то клиент при каждом срабатывании будет попадать в одну и ту же ветку.» → Единственный вендор с безусловным per-person стикингом по умолчанию. Источник: help.mindbox.ru/docs/workflow-ab-tests.


7. Сводная таблица

Вендор Split как Кол-во веток Проценты Стикинг при повторном входе Окно атрибуции Exit-on-goal
Customer.io Random Cohort (отд. нода) до 20 вручную, Σ=100% per-cohort (Profile/Object) до 90 дн (настр.) НЕ авто; через exit conditions
Braze bucket 0–9999 + ручной сегмент сколько диапазонов вручную через диапазоны персистентный bucket (де-факто стики) ≥ длиннейшей ветки; +3 дня; min 5 мин exit event (может = conversion)
Segment v1 Randomized Split до 5 вручную, Σ=100% стики, если есть re-entry condition — (не в скоупе фактов)
Segment v2 Randomized Split до 5 вручную, Σ=100% по умолч. ре-рандом, опция «Assign same branch»
Klaviyo conditional split + «Random sample» YES/NO (можно цепочкой) % на YES-путь — (не в скоупе фактов) пер-канальное (email 5д, SMS 5д/1д, push 24ч…)
Mindbox A/B-тест в сценарии (не уточнено) (не уточнено) безусловный per-person стикинг

Прочерки — фактов харнесс по этой ячейке не вернул, а не «функции нет».


8. Выводы и развилки под наши RANDOMIZER и GOAL

8.1 Развилка №1 — модель фиксации распределения (главная)

Задача MLF-296 требует «фиксацию распределения контактов». Варианты:

8.2 Развилка №2 — проценты: сумма 100% жёстко или авто-остаток

8.3 Развилка №3 — окно атрибуции: единое или пер-канальное

8.4 Развилка №4 — exit-on-goal

Ресёрч подтверждает: exit-on-goal — явный переключатель, не дефолт. У нас уже есть флаг stopFlow на GOAL (ADR-500 §11) — оставляем как есть, ресёрч валидирует решение. Нюанс из Braze для рантайма: если контакт в PAUSE-шаге в момент достижения цели — решить, выводим сразу или после окончания паузы (Braze досиживает Delay). Уточнить в §8.5.

8.5 Черновик расширений схемы (для обсуждения, НЕ финал)

// RANDOMIZER.data
{
  "branches": [                 // N ветвей
    { "id": "branch_0", "label": "A", "weight": 50 },
    { "id": "branch_1", "label": "B", "weight": 50 }
  ],                            // Σ weight === 100 (валидатор блокирует иначе)
  "sticky": true                // MVP: всегда true (per-person фиксация). Развилка §8.1
}

// GOAL.data — добавляется к текущим goalName/goalValue/currency/stopFlow
{
  "attributionWindow": { "value": 7, "unit": "days" },  // НОВОЕ, развилка §8.3
  "goalEvent": "order_completed"                        // целевое событие (уточнить связь с текущим goal_reached)
}

Атрибуция на ветку (метрика конверсии по веткам): при достижении цели контактом, чьё execution прошло через RANDOMIZER, засечь его branch_id и инкрементить конверсию этой ветки в cdp.automation_analytics_events. Механику первичные доки не раскрывают — проектируем сами (§8.6).

8.6 Что у конкурентов НЕ подсмотрели (наш дифференциатор + риск)

Явной, задокументированной механики «атрибуция достижения цели на конкретную A/B-ветку + конверсия по веткам на нодах» ресёрч не нашёл ни у кого (Customer.io лишь декларирует цель, без контракта). Значит: (а) это реальный дифференциатор «умной платформы»; (б) риск — проектируем без референса, нужен собственный аккуратный дизайн атрибуции.


9. Открытые вопросы для согласования с М. Терентьевым

  1. Фиксация распределения (§8.1): берём безусловный per-person стикинг (Mindbox-стиль) или делаем опцией с дефолтом-ре-рандом (Segment v2)? Рекомендация: безусловный, MVP.
  2. Старт окна атрибуции (§8.3/8.5): отсчитывать от входа контакта в сценарий, от прохождения GOAL-ноды, или от последнего касания (сообщения)? У вендоров — от отправки сообщения; у нас касания может не быть в этой ветке.
  3. Exit-on-goal в момент паузы (§8.4): если контакт в PAUSE и достиг цели — выводить немедленно или после окончания паузы (как Braze с Delay)?
  4. Атрибуция на ветку (§8.6): какой глубины метрика нужна в MVP — просто «конверсия % по ветке на ноде», или ещё ценность (goalValue) и стат-значимость winner (как Braze)?
  5. Целевое событие: цель — это произвольное cdp-событие (заказ и т.п.) или существующая GOAL-нода goal_reached? Нужно развести «цель как отдельное событие» и «GOAL-нода как маркер в графе».

10. Ограничения ресёрча


11. Источники

Customer.io: branches · random-cohort · conversions Braze: random_bucket_numbers · multivariate_analytics · exit_criteria Segment / Twilio Engage: v1/step-types · v2/event-triggered-journeys-steps Klaviyo: message attribution · A/B test flow branches · Academy — attribution Mindbox: workflow-ab-tests


12. Следующий шаг (шаг 2 карточки)

Макеты в Claude Design: (1) нода RANDOMIZER на холсте (N выходов с процентами + валидатор Σ=100%) и её инспектор (ветки, веса, тумблер sticky); (2) конфигуратор GOAL (целевое событие + окно атрибуции + stopFlow exit-on-goal) и отображение конверсии по веткам на нодах. До апрува макетов М. Терентьевым в разработку НЕ берём (DoD карточки).