На отчёте treatment выглядит лучше control, но numerator и denominator собраны из разных наборов. Иногда это случается после невинной оптимизации: страница перестаёт перезагружаться, клиентский event теряется или cohort получает другое окно. Цена ошибки — false positive: команда объясняет пользователю эффект, которого не было, и выпускает изменение с неизвестным ущербом.
Причина не в самой дроби. Любая ratio скрывает состав числителя и знаменателя. Проверка — разложить metric на набор субъектов, события и период, затем убедиться, что treatment и control отвечают на один и тот же вопрос. Действие — сделать эти условия частью result; если хотя бы одно не выполнено, решение получает stop status.
Metric — это контракт, а не имя на графике
В fixed model conversion задан как unique subjects с checkout_confirmed, делённое на unique subjects с checkout_opened, внутри одного cohort и одного дня. Такой contract намеренно мал. Он не говорит, сколько ждать пользователя, как обрабатывать два устройства и что считать «успешным заказом». Но он не даёт случайно заменить denominator на all-events и выдать плотность telemetry за поведение людей.
| Сбой | Почему delta нельзя читать | Машинный result | Ремонт |
|---|---|---|---|
| Нет attribution | confirm не связан с вариантом | missing-attribution-rule | добавить ключ связи и test |
| Смешан period | группы не наблюдались в одном окне | mixed-cohort-or-period | зафиксировать окно до запроса |
| Неверный denominator | ratio отвечает на другой вопрос | wrong-denominator | считать unique opened subjects |
| Guardrail деградирует | локальный выигрыш куплен отказами | eligible, но human hold | разобрать error path |
Проверить ratio до интерпретации
Numerator — число подтверждений, denominator — число открывших, но оба значения имеют смысл только вместе с правилом inclusion. Cohort здесь означает вариант сравнения, attribution связывает подтверждение с попыткой, а guardrail описывает недопустимое ухудшение рядом. Эти термины не доказывают причинность: они лишь делают видимыми условия, без которых ratio отвечает на другой вопрос.
import { createFixedProductMetricInput, inspectFixedProductMetric, prepareFixedProductDecision } from './upgrade-2025-07.mjs';
const report = inspectFixedProductMetric(
createFixedProductMetricInput('fixed-wrong-denominator-v1'),
);
const decision = prepareFixedProductDecision(report);
console.log({ accepted: report.accepted, reasons: report.reasons, status: decision.status });
// Expected: wrong-denominator and stop-before-product-decision.
// The input is fixed synthetic data in memory; no metric is sent or published.
Этот пример не вычисляет «правильную conversion» задним числом. Он показывает, что имя метрики не переносится на другой denominator. Report с all-events получает stop до human decision, хотя набор событий внешне похож на valid case. Для реального расчёта отдельно нужны randomization, задержка доставки, политика идентификаторов и проверка pipeline.
Порядок проверки сравнения
- Назвать decision. Сформулировать, какое действие будет разрешено или остановлено, а не просто открыть dashboard.
- Зафиксировать population. До запроса записать cohort, period, inclusion и attribution.
- Разложить дробь. Показать numerator и denominator отдельно и проверить, что они относятся к одной задаче.
- Положить рядом guardrail. Сравнить его по тому же окну и назвать владельца порога.
- Вернуть HOLD при разрыве. Repair contract предшествует product discussion.
Все события, варианты, результаты и решения ниже — fixed synthetic JS literals. Модуль не читает файлы, сеть, clock, telemetry, Git, CI, production или user data и не выполняет side effect.
Почему guardrail живёт рядом, а не в конце отчёта
Guardrail не обязан быть «самой важной» метрикой. Его работа проще: заранее назвать ухудшение, которое делает локальный выигрыш недостаточным. В synthetic наборе один render_failed у двух opened в control не создаёт сравнения для реального продукта. Он показывает контракт: failure имеет тот же cohort и тот же denominator base, поэтому его нельзя потерять при смене панели. В реальном проекте порог и owner определяются до запуска, а не после удачного результата.
Работа Safe Velocity описывает guardrail как показатель, который не должен ухудшаться при rollout, и local metric как средство объяснить изменения. Нельзя перевернуть эту фразу в гарантию: если local metric вырос, значит outcome улучшился. Между ними остаются выборка, вариант, сезонность, качество событий и другие механизмы. Поэтому автор оставляет человеческое решение последним шагом и требует доказательства, достаточного для конкретного риска.
Разбор numerator и denominator
Работа Microsoft о metric pitfalls особенно полезна именно здесь: она показывает пример, где другой состав наблюдений делает delta ненадёжной, и предлагает декомпозицию numerator и denominator. Наше практическое следствие скромнее: вместе с числом хранить список правил, из которого оно получено. Если после изменения request path исчезла часть opened, alert должен говорить о denominator, а не радоваться conversion.
Проверка в модуле добавляет один confirm из следующего дня. Результат mixed-cohort-or-period останавливает расчёт до сравнения. Это не статистический тест и не защита от всех ошибок: код не проверяет рандомизацию, задержку доставки или личность subject. Зато он делает распространённую подмену видимой и не позволяет default-фильтру quietly собрать удобную выборку.
Ограничение и следующий шаг
Не делайте из guardrail универсальный список. У одной операции критичен отказ, у другой — отмена, доступность или безопасность; метрика получает смысл только рядом с пользовательским решением и владельцем риска. Следующий шаг: возьмите одну ratio из своего dashboard, напишите её numerator и denominator словами, затем подайте в test события из другого периода. Ожидаемый результат — расчёт остановлен с причиной, которую может исправить конкретный owner.
Историческая граница июля 2025
Microsoft Research PDF 2017 года использован для риска sample/metric mismatch, а работа 2019 года — для ролей local, success и guardrail. OpenTelemetry v1.31.0 закреплён commit от марта 2025. Они не доказывают причинность fixed example и не задают пороги. Структура decision record и её stop reasons — ограниченный проектный выбор автора.
Проверяемые источники
- OpenTelemetry Semantic Conventions v1.31.0, events (immutable commit c01aa89, 11 March 2025) — версия: tag v1.31.0; immutable commit c01aa89d9a13042e56536c60975139c50e764796, 2025-03-11. Событие имеет уникальное имя; структура события и применимые attributes должны быть документированы, а dynamic values не должны становиться частью имени. Граница: Это соглашение о семантике telemetry. Оно не определяет продуктовую метрику, causal effect, выбор denominator или критерий ship.
- Microsoft Research: Safe Velocity with Controlled Rollouts (ICSE-SEIP 2019) — версия: ICSE-SEIP 2019 author version, published 2019; HTTPS checked 2026-07-31. Работа различает local feature, success и guardrail metrics; guardrail нужен, чтобы выпуск не ухудшал важные показатели, а local metric помогает объяснить движение более общей метрики. Граница: Это описание controlled rollouts Microsoft. Оно не доказывает, что любое изменение local metric вызвало пользовательский результат в другом продукте.
- Microsoft Research: A Dirty Dozen Metric Interpretation Pitfalls (KDD 2017) — версия: KDD 2017 author version, published 2017; HTTPS checked 2026-07-31. Работа показывает, что разные наборы наблюдений в treatment и control делают metric delta недостоверной; рекомендует разбирать numerator и denominator и отслеживать telemetry loss. Граница: Пример относится к controlled experiments. Он не заменяет дизайн эксперимента, расчёт мощности, privacy policy или проверку конкретного pipeline.