DarkRiDDeR12 мин

Факт, решение, эксперимент: контракт postmortem без заднего знания

АрхитектураНадёжность

Дорогой дефект postmortem — не отсутствие шаблона, а смешение времён. Строка «релиз вызвал ошибку, поэтому инженер откатил его» содержит разные утверждения: был ли релиз, когда появился симптом, что было известно до отката и есть ли доказательство связи. В одной фразе позднее объяснение выглядит как факт, доступный во время решения.

Цена этой подмены — плохой следующий change. Команда берёт самый заметный элемент из истории, объявляет его причиной и добавляет защиту именно вокруг него. Если связь была случайной, новая проверка создаёт работу, но не улучшает способность заметить похожее состояние. Механизм без поиска виноватого проще: каждое утверждение получает тип, тип задаёт допустимые поля и не разрешает сделать больший вывод, чем дают записи.

Контракт из трёх типов records

Первый тип — факт. Он хранит минимальное описание и evidence reference, но не root cause. Второй — решение в моменте. Оно хранит действие, время и set фактов, доступных перед выбором; поле оценки остаётся `not-judged`, пока команда не проведёт отдельную проверку. Третий — профилактический experiment. Он описывает гипотезу, метод, success criterion и rollback. Его `expectedEffect` остаётся `not-evaluated`, потому что задача ещё не стала результатом.

Контракт полей и граница вывода
RecordГраница ответственностиОбязательная связьЧто запрещено в модели
factзафиксировать предмет и источникtimestamp + evidence referenceculprit, root cause, real effect
decision-at-the-timeпоказать выбор при известной информацииordered list of fact IDsимя человека как объяснение, оценка задним числом
preventive-experimentпроверить одну управляемую гипотезуcriterion + rollbackобещание предотвращения реального инцидента
evidence cardназвать разрешённый выводссылки на все три record typeподмена модели production observation
Учебная карточка решения: три synthetic fact IDs входят в решение, а выходом становится один профилактический experiment с критерием и rollback. Отдельная перечёркнутая ветка показывает, что имя человека не является полем объяснения.
Схема показывает границы контракта records. Она не реконструирует реальный incident, не отражает чат, alert, лог, trace, роль человека или влияние production-изменения.

Факт не обязан объяснять механизм

Инженеру бывает неудобно оставить в документе фразу «причина не подтверждена». Кажется, будто работа не сделана. Но факт-карточка полезна именно тем, что переживает смену гипотезы. Если позже выяснится другой механизм, timestamp и ссылка на исходный артефакт останутся валидными; ложное объяснение придётся вычёркивать вместе со всеми задачами, которые на нём выросли. Поэтому `fact` в модели имеет поле `inference=not-a-cause-claim`.

Это не призыв собирать бесконечный архив. Для каждой строки спросите: помогает ли она связать симптом с моментом решения или проверить следующий experiment? Если нет, текст можно вынести в приложение либо удалить. Контракт должен быть небольшим, чтобы review замечал отсутствие источника. В fixture второй fact отклоняется, если `evidenceRef` пуст. Такая проверка не подтверждает существование артефакта, но не разрешает сделать вид, что источник указан.

Решение — снимок доступной информации

У решения есть направление во времени. `availableFactIds` ссылаются только на facts, которые стоят раньше `occurredAt` решения. Это важно технически: полная timeline после разбора может содержать новые логи, комментарии или результаты эксперимента, но они не должны доказывать, что исходный выбор был неразумным. Нельзя изменить прошлую границу знаний добавлением удобного факта в список. Fixture специально отклоняет decision с неполным expected set и вариант с временем до третьего fact.

Модель не содержит `actor`: это не потому, что действия происходят сами, а потому, что имя человека не объясняет состояние системы. В реальном документе владелец action item нужен, а персональные данные и доступ к ним требуют отдельного правила. Но для вопроса «какие условия сделали решение возможным?» полезнее поля: какая версия была известна, какой сигнал доступен, какая инструкция существовала, какое действие было обратимо. Они дают основу для change в системе, runbook или интерфейсе, а не ярлык для участника.

Experiment отделяет профилактику от обещания

Профилактическая задача часто начинается с глагола «добавить»: alert, тест, лимит, checklist. Этого недостаточно для проверки. В контракте experiment должен отвечать: какую неопределённость мы хотим уменьшить, каким минимальным методом, что будет считаться прохождением и как вернуть предыдущую точку. Например, гипотеза может касаться только явного reversible checkpoint в one runbook. Она не заявляет, что это устранит все outage или изменит реальный metric.

Критерий стоит сделать бинарным и связанным с артефактом: «у каждого опасного действия есть owner role, stop criterion и rollback reference». Такой критерий можно review-ить без доступа к production. Если он не проходит, результат — не «команда не справилась», а конкретное отсутствие полей. Затем можно выбрать меньший experiment либо перенести работу туда, где доступна настоящая среда. CISA и NIST полезны здесь как дисциплина follow-up в incident response, а не как разрешение объявить любую задачу достаточной защитой.

Выполните fixture как проверку формы

`assembleSyntheticPostmortem()` не получает JSON-файл, API response или вывод CI. Он берёт экспортированный constant из того же модуля. Функция проверяет fixed IDs, порядок пяти synthetic records, полное множество fact IDs, отсутствие полей `culprit`, `rootCause` и `realEffect`, а также rollback у experiment. На valid branch строится immutable card, где permitted conclusion ограничен формой records. Это намеренно не schema validator для вашего формата и не engine root-cause analysis.

import {
  assembleSyntheticPostmortem,
  runPostmortemFixture,
  syntheticIncidentRecords,
} from './upgrade-2023-11.mjs';

const card = assembleSyntheticPostmortem(syntheticIncidentRecords);
if (!card.accepted) throw new Error(card.reason);

const report = runPostmortemFixture();
if (!Object.values(report.assertions).every(Boolean)) throw new Error('fixture failed');

console.log(card.evidence.permittedConclusion);
// record-boundaries-present-in-fixed-synthetic-model

// Только fixed synthetic records в памяти. Нет I/O, сети, CI,
// logs, traces, alerts, users или production runtime.

node web/scripts/upgrade-2023-11.mjs --verify-fixture

# Fixture не запускает сборку, CI, сеть, production runtime или внешние инструменты.
# Его PASS не является причиной, impact assessment или результатом профилактики.

Полезный результат fixture — отказ. В нём видна конкретная граница: например, `decision-context-contract-rejected` означает, что у решения нет ожидаемого набора facts, а не что человек сделал неверный выбор. `culprit-cause-or-real-effect-claim-rejected` означает, что в учебную модель добавили вывод, который модель обещала не делать. Это даёт редактору короткую причину вернуть абзац на доработку без психологической оценки участников.

Маршрут: симптом → причина → проверка → действие

  1. Симптом. Одна фраза postmortem одновременно называет событие, виновника, причину и профилактику.
  2. Причина. В документе нет типов records и временной границы знания; поздний факт выглядит доступным в моменте.
  3. Проверка. Разделите предложение на fact, decision и experiment. Для decision перечислите только предшествующие fact IDs; для experiment назовите criterion и rollback.
  4. Действие. Сохраните facts в неизменяемой timeline, decision привяжите к доступной информации, а профилактику перепишите как ограниченный эксперимент.
  5. Проверка вывода. Найдите слова «вызвал», «виноват», «предотвратит» и потребуйте отдельный источник либо смените формулировку на hypothesis или unknown.
  6. Следующий шаг. Добавьте один review gate: новый action item не появляется в списке, пока не имеет owner role, проверяемый результат и обратимый путь.

Обратимость относится к изменению, не к тексту

Иногда rollback описывают так, будто документ сам способен вернуть систему назад. Это опасная метафора. Ретроспектива может зафиксировать, что нужно откатить, и спросить про критерий завершения; она не знает, выполнено ли действие, пока не получит разрешённое evidence. В модели rollback — значение `restore-synthetic-record-snapshot`. Оно возвращает только копию локального набора и явно не создаёт внешнего эффекта.

В production-решении rollback должен быть точнее: target configuration, безопасная последовательность, владелец роли, stop criterion, способ проверить отсутствие дальнейшего воздействия и границы доступа. Если хотя бы один пункт неизвестен, его лучше оставить открытым. Открытый риск — не поражение postmortem; хуже спрятать его под словом «откат» и обнаружить несогласованность во время следующего инцидента.

Ограничения и следующий шаг

Это не реальная incident database и не спецификация хранения. Fixture не читает, не отправляет и не производит настоящие incident data, logs, traces, alerts, users, CI, сеть или production runtime. Все identifiers, timestamps, sources, decisions и experiments fixed synthetic. Ни одна assertion не говорит о виновнике, причине, impact, пользователе, метрике, доступности, безопасности или эффекте настоящего изменения. Она проверяет только различение типов внутри учебной формы.

Следующий шаг — провести design review одного будущего postmortem template. Уберите из поля facts интерпретации, добавьте к decision список доступной информации и обязуйте preventive task иметь success criterion plus rollback. Затем на одном разрешённом учебном случае проверьте, хватает ли этих полей читателю, который не был на incident call. Если не хватает, добавляйте не историю о людях, а недостающий артефакт, вопрос или границу ответственности.

Историческая граница ноября 2023

Материал ограничен официальными источниками, доступными до конца ноября 2023: Google SRE Book 2017 описывает postmortem как документ с impact, действиями и follow-up; его example содержит timeline и action items. NIST SP 800-61 Rev. 2 (2012) и CISA playbooks (2021) относятся к cybersecurity incident response и follow-up. Из них не следует универсальный schema, юридическая обязанность или доказанный эффект именно этой модели; contract выше — учебная инженерная декомпозиция.

Проверяемые источники

  • Google SRE Book: Postmortem Culture: Learning from Failure, 2017 — официальная публикация Google, доступная до ноября 2023. Она описывает опыт и практику Google: документирование инцидента, разбор contributing causes, review и action items. Это не универсальное доказательство эффекта для другой команды.
  • Google SRE Book: Example Postmortem, 2017 — официальный учебный пример с timeline, impact, action items и lessons learned. Он показывает форму артефакта, но не является данными этого fixture или причиной какого-либо чужого сбоя.
  • NIST SP 800-61 Revision 2: Computer Security Incident Handling Guide, август 2012 — официальное руководство по обработке компьютерных security-инцидентов, включая phase post-incident lessons learned. Его область — incident response в security, а не готовый шаблон для любого продуктового или эксплуатационного разбора.
  • CISA: Federal Government Cybersecurity Incident and Vulnerability Response Playbooks, ноябрь 2021 — официальный федеральный playbook США, опубликованный до ноября 2023. Он относится к FCEB cybersecurity response; статья не переносит его обязательства, сроки или полномочия в иной контур.