{ "index": 149, "slug": "editorial-2023-11-mechanism-postmortem", "title": "Postmortem без заднего знания: как связать факт, решение и действие", "excerpt": "После сбоя команда легко принимает позднюю гипотезу за причину. Разбираем временную границу знания, контракт записей и проверяемый профилактический шаг.", "contentHtml": "
После сбоя в чате появляется короткое объяснение: «релиз сломал обработку, поэтому инженер откатил его». В одной фразе смешаны событие, причина, решение и оценка. Но в момент отката команда могла не знать, был ли виноват релиз. Она могла видеть только рост ошибок и доступный способ остановить поток.
\nЦена ошибки — не неточная формулировка. Команда ставит защиту вокруг самого заметного элемента истории. Она добавляет проверку к релизу, хотя сбой мог возникнуть из-за данных, лимита или внешней зависимости. Следующий разбор повторяет ту же подмену. Postmortem становится рассказом задним числом, а не инструментом изменения системы.
\nРабочая модель разделяет три записи: наблюдаемый факт, решение с доступной в тот момент информацией и будущую проверку гипотезы. Время ограничивает вывод. Поздний лог может объяснить событие, но не доказывает, что этот лог был доступен оператору при выборе. Так документ сохраняет неизвестное и показывает, какое действие нужно проверить.
\nФакт описывает то, что можно привязать к источнику: время, сигнал, значение поля, изменение состояния. Он не обязан содержать причину. Запись «в 10:03 доля ответов 5xx превысила порог» сильнее записи «сервис упал из-за релиза», если связь с релизом ещё не проверена.
\nРешение описывает действие и снимок доступных фактов. Его нельзя оценивать полным набором данных, который появился позже. Иначе документ наказывает человека за информацию, которой у него не было, и скрывает вопрос к системе: почему нужный сигнал, инструкция или безопасный способ остановки не были доступны раньше.
\nЭксперимент переводит гипотезу в проверяемую работу. Он должен назвать один риск, способ проверки, критерий успеха и обратный путь. Фраза «добавить больше мониторинга» не даёт критерия. Фраза «для этого маршрута появляется alert при трёх последовательных ошибках, а дежурный подтверждает его в тестовом окружении» уже задаёт проверку формы. Она всё ещё не доказывает эффект в production.
\n| Слой | Что записать | Что не утверждать |
|---|---|---|
| Факт | Время, наблюдение и ссылка на лог, метрику или change. | «Это точно причина» без проверки связи. |
| Решение | Действие и факты, доступные до него. | Оценку через поздние данные. |
| Гипотеза | Какой механизм нужно проверить. | Причину, если она пока только предполагается. |
| Эксперимент | Критерий, владелец роли и rollback. | Обещание предотвратить любой повтор. |
У каждой записи есть occurredAt. У решения есть availableFactIds. В список попадают только факты, которые уже существовали до решения. Это простое правило удерживает границу знания. Новая запись может изменить гипотезу о причине, но не меняет набор данных, на котором приняли исходное решение.
Рассмотрим учебный пример. Он не читает реальные логи и не описывает настоящий инцидент. В нём зафиксированы три факта, решение остановить проверку изменения и эксперимент с обратным путём.
\n{\n \"facts\": [\n {\"id\": \"f-01\", \"at\": \"10:00\", \"text\": \"доля ответов 5xx выросла\", \"source\": \"metric-card-01\"},\n {\"id\": \"f-02\", \"at\": \"10:03\", \"text\": \"изменена версия конфигурации\", \"source\": \"change-02\"}\n ],\n \"decision\": {\n \"at\": \"10:05\",\n \"action\": \"остановить продвижение\",\n \"availableFactIds\": [\"f-01\", \"f-02\"]\n },\n \"experiment\": {\n \"hypothesis\": \"явная проверка версии сократит время обнаружения\",\n \"successCriterion\": \"проверка видна в тестовом сценарии\",\n \"rollback\": \"удалить проверку и вернуть прежнюю конфигурацию\"\n }\n}\nКод показывает форму, а не результат. В реальном документе source должен указывать разрешённый артефакт, который команда действительно может открыть. Время должно использовать одну часовую зону. Если источник недоступен, это нужно записать как ограничение, а не заменить догадкой.
Модель допускает, что причиной окажется не изменение версии. Например, поздняя проверка покажет исчерпанный лимит внешнего сервиса. Тогда факты и исходное решение остаются полезными. Меняется гипотеза и, возможно, эксперимент. Нельзя переписать факт так, чтобы он заранее подтверждал новую версию.
\n| Симптом | Вероятная причина записи | Проверка | Действие |
|---|---|---|---|
| В первом абзаце назван виновник. | Имя человека используется как объяснение состояния. | Убрать имя и спросить, какое условие системы нужно изменить. | Записать владельца будущего действия отдельно от причины. |
| Решение выглядит очевидным после чтения всей timeline. | К решению добавили факты, появившиеся позже. | Сравнить время решения с каждым availableFactId. | Оставить только предшествующие факты и сохранить unknown. |
| Action item звучит как «добавить мониторинг». | Гипотеза не имеет измеримого критерия. | Спросить, какой артефакт должен измениться и как увидеть проход. | Указать сигнал, порог, владельца роли и rollback. |
| После исправления обещают отсутствие повторов. | Учебная проверка выдана за production-результат. | Найти источник эффекта и период наблюдения. | Сузить вывод до «проверяет форму» или собрать реальные данные. |
Отсутствие поиска виноватого не отменяет ответственности. В документе должны быть владельцы действий, сроки и правила эскалации. Но роль владельца отвечает на вопрос «кто доведёт изменение», а не на вопрос «почему система оказалась в таком состоянии». Для второго вопроса нужны условия: доступный сигнал, версия инструкции, права, лимит, автоматическая защита или отсутствие безопасной остановки.
\nПолезно отделить две оценки. Первая: было ли действие разумным при доступной информации? Вторая: какие условия сделали такой выбор вероятным? Первая требует воспроизвести границу знания. Вторая ведёт к изменению интерфейса, runbook, алерта или архитектуры. Поздняя причина может помочь второй оценке, но не должна подменять первую.
\nОтрицательный путь важен не меньше положительного. Если источник не открывается, поле остаётся неизвестным. Если rollback нельзя выполнить безопасно, эксперимент не готов. Если критерий нельзя проверить без production-доступа, нужно сначала спроектировать безопасную проверку или признать границу. Документ не должен заполнять пробелы уверенным тоном.
\nЭта модель не заменяет incident command, расследование безопасности, юридическую оценку или правила хранения персональных данных. В security-контуре источники и доступы требуют отдельной политики. В распределённой системе часы могут расходиться, а источник может измениться после события. Тогда нужно хранить версию артефакта, часовой пояс и допустимый уровень точности.
\nТри слоя не доказывают причинность. Они только не дают написать вывод шире доступных данных. Причинную связь проверяют отдельными методами: воспроизведением, сравнением изменений, экспериментом или анализом данных. Если эти методы недоступны, корректная формулировка — «причина не подтверждена».
\nУчебный JSON выше фиксирует структуру и отрицательный путь. Он не запускается на настоящей инфраструктуре, не читает метрики и не измеряет влияние. Не переносите его идентификаторы, время и критерий в production без адаптации к своим источникам, ролям и процедурам отката.
\nPostmortem готов к техническому review, если независимый читатель может открыть источник каждого факта, увидеть, что решение ссылается только на предшествующую информацию, и проверить один профилактический эксперимент по его критерию. Если хотя бы один пункт не выполняется, статус должен быть «не готов», а следующий шаг — устранение конкретного пробела: источник, временная граница, критерий или rollback.
\n