# Как подтверждение инцидента ИИ сохраняет его открытым

Агент, который подтвердил оповещение, сообщил лишь один полезный факт: человек или система взяли на себя расследование. Агент не доказал, что сервис для клиентов восстановился, условие оповещения исчезло, а следующему дежурному больше не нужно быть наготове. Интеграция, которая превращает подтверждение в закрытие, стирает эту разницу и вносит в журнал инцидента выдуманное событие.

Считайте действия с инцидентом отдельными переходами состояния и выдавайте для каждого свои права. Подтверждение, закрытие, подавление и маршрутизация могут стоять рядом в интерфейсе пейджера, однако отвечают на разные рабочие вопросы. Агент должен вызывать самое узкое действие, человек должен согласовывать переход с серьезными последствиями, когда этого требует политика, а журнал аудита должен называть обоих участников.

## Подтверждение фиксирует ответственность, а не восстановление

Подтверждение означает, что дежурный принял оповещение и начал расследование. Оно меняет того, от кого теперь ждут действий, и часто влияет на эскалацию. Оно ничего не говорит о том, сохраняется ли сбой.

Документация PagerDuty Incidents прямо разделяет эти понятия: подтвержденный инцидент уже расследуют, но еще не устранили. Подтверждение закрепляет ответственность и приостанавливает эскалацию до истечения срока, а закрытие означает, что проблему исправили. Этот срок важен. Если никто не закроет инцидент вовремя, PagerDuty может вернуть его в состояние triggered и возобновить эскалацию. Агент, который закрывает инцидент при подтверждении, незаметно убирает эту защиту.

Google Cloud Monitoring использует немного другие термины, но проводит ту же границу. Его документация определяет Acknowledged как открытый инцидент, который человек вручную отметил во время расследования. Там также сказано, что подтверждение не прекращает повторные уведомления. За уведомления отвечает пауза или изменение политики, а закрытие происходит после наблюдения восстановления, ручного действия или выполнения условия автоматического закрытия. Такое поведение предупреждает: у глаголов в интерфейсе пейджера нет одинаковых побочных эффектов.

Практический контракт должен быть простым: `acknowledge` записывает ответственного, время подтверждения и участника, который принял работу. Если пейджер поддерживает такую возможность, действие может приостановить эскалацию. Оно обязано оставить состояние восстановления открытым, сохранить активные оповещения и не менять правила уведомлений или маршрутизации, пока вызывающая сторона не запросит другое действие через отдельный механизм.

Эта граница защищает и метрики. Если подтверждение закрывает запись, время до подтверждения и время до восстановления сливаются в одну временную метку. Команда начинает поощрять быстрые нажатия кнопки и теряет показатель, который описывает реальную длительность проблем у пользователей. Разбор инцидента наследует ту же ошибку: хронология утверждает, что сервис восстановился до того, как сработало временное исправление.

## Один глагол агента должен означать один переход

Каждый инструмент агента должен предоставлять один рабочий глагол и один основной эффект. Связанные действия кажутся удобными на спокойном обсуждении архитектуры, но во время сбоя разобраться в них невозможно.

Подтверждение отвечает на вопрос, кто принял работу. Оно записывает ответственного и время, но не означает восстановление сервиса или исчезновение оповещения. Закрытие отвечает на вопрос, закончился ли инцидент. Оно закрывает запись после получения доказательств восстановления и не должно попутно заглушать будущие оповещения или менять владельца.

Подавление отвечает на вопрос, должен ли выбранный сигнал создать инцидент или отправить уведомление. Оно блокирует выбранные уведомления или создание инцидентов в заданной области, но не восстанавливает уже открытый инцидент. Маршрутизация отвечает на вопрос, кто должен получить работу или стать ответственным. Она меняет сервис, команду, цепочку эскалации или исполнителя, не утверждая, что получатель подтвердил либо закрыл инцидент.

Эти определения задают границу полномочий. Человек может разрешить агенту подтверждать все оповещения своей команды, но требовать согласования перед закрытием. Тот же человек может допускать подавление лишь во время объявленного обслуживания, а маршрутизацию только между двумя сервисами. Широкое право `manage_incident` не выражает эти ограничения без скрытой логики.

Не создавайте инструмент `handle_page` с флагами `ack`, `mute`, `assign` и `close`. Модель будет выбирать набор действий по тексту, и одна неверно понятая фраза приведет к нескольким изменениям. Раздельные инструменты вынуждают вызывающую сторону явно указать намерение и позволяют шлюзу отдельно разрешать каждый переход.

Разделение должно сохраняться в адаптерах разных поставщиков. Если один поставщик называет временное отключение уведомлений snooze, а другой downtime, адаптер может сопоставить оба названия с единым намерением `suppress_notifications`. Нельзя считать подавление и закрытие взаимозаменяемыми лишь потому, что оба действия способны сделать пейджер тихим.

## Безопасный API не позволяет выразить запрещенную комбинацию

Узкая схема запроса предотвращает больше инцидентов, чем хитрая инструкция для модели. Следующий запрос способен подтвердить один существующий инцидент и не может незаметно добавить закрытие, отключение уведомлений или переназначение.

```json
{
  "operation": "incident.acknowledge",
  "incident_id": "inc_01JQ8K4Q6M",
  "expected_version": 17,
  "actor": {
    "type": "agent",
    "session_id": "ses_01JQ8JY2P3"
  },
  "reason": "Accepted investigation after the database latency page"
}
```

Проверяемые сведения об участнике должен добавлять сервер, а не агент. Модель может указать причину, но ей нельзя доверять хеш собственного исполняемого файла, личность из подписи кода, учетную запись пользователя или результат согласования. Шлюз получает эти значения из аутентифицированного процесса и канала согласования.

Успешный ответ должен описывать точный переход и состояние, которое осталось неизменным:

```json
{
  "operation_id": "op_01JQ8K5D7A",
  "incident_id": "inc_01JQ8K4Q6M",
  "transition": "triggered_to_acknowledged",
  "incident_status": "acknowledged",
  "recovery_status": "open",
  "version": 18,
  "approved_by": "usr_2048",
  "approved_at": "2026-07-24T02:14:31Z"
}
```

Поле `recovery_status: open` может показаться лишним. Оставьте его. Агенты часто продолжают рассуждение по последнему ответу, а явное состояние обходится дешевле, чем догадка модели о смысле терминов поставщика. Ответ также дает оркестратору стабильную проверку: подтверждение прошло, а восстановление осталось открытым.

Не принимайте в запросе подтверждения противоречивые вспомогательные поля вроде `resolve_if_healthy`, `mute_for` или `route_to`. Они снова превращают один endpoint в пакет действий. Если процессу нужно второе действие, он должен отправить второй запрос, получить отдельное решение и оставить отдельное событие аудита.

## Согласование должно относиться к конкретному переходу

Согласование должно разрешать описанное изменение состояния, а не выдавать агенту абстрактное доверие. Разрешение на сессию может подтвердить, что известный процесс вправе работать, но оно не должно автоматически разрешать любые изменения инцидентов, которые процесс найдет позднее.

Для каждого перехода записывайте предложенную операцию, целевой инцидент, состояние до решения, запрошенную область, сессию агента, согласовавшего человека, время и способ согласования. Добавляйте версию состояния или идентификатор события поставщика, которые видел человек. Без такой связи карточку для инцидента A можно повторно применить к инциденту B, а решение, принятое в состоянии triggered, можно выполнить после того, как другой дежурный уже закрыл инцидент.

Экран согласования должен говорить на языке эксплуатации. Формулировку «Подтвердить инцидент задержки базы данных inc_01JQ8K4Q6M и передать расследование дежурной группе Payments» можно осмысленно проверить. Формулировку «Разрешить действие агента» проверить нельзя. Для закрытия показывайте приведенные агентом доказательства восстановления и перечисляйте, что остается активным. Для подавления показывайте точную область сигнала, длительность и срок окончания. Для маршрутизации показывайте текущего и предложенного получателя.

Храните четыре личности, не сводя их в расплывчатое поле `actor`:

- Инициатором выступает сессия агента, предложившая изменение.
- Согласующим выступает человек, который разрешил действие, когда согласование требовалось.
- Исполнителем выступает шлюз или интеграция, вызвавшая систему поставщика.
- Объектом выступает измененный инцидент, оповещение, сервис или маршрут.

При проверке эти личности отвечают на разные вопросы. Инициатор объясняет запуск автоматизации. Согласующий подтверждает полномочия человека. Исполнитель связывает событие с учетными данными и журналами поставщика. Объект не дает перенести правильное решение на другой ресурс.

Sallyport может требовать отдельного согласования для каждого вызова HTTP API или действия SSH, если сохраненный ключ так настроен. Учетные данные остаются в зашифрованном хранилище и никогда не попадают к агенту. Такой механизм подходит для переходов инцидента, поскольку решение привязывается к конкретному запросу поставщику, а не к свободному обещанию модели.

## Гонки превращают правдоподобную автоматизацию в ложную хронологию

Состояние инцидента меняется, пока агент рассуждает, ждет согласования или повторяет сетевой запрос. Система, которая игнорирует эту задержку, рано или поздно подтвердит закрытый инцидент, заберет работу у активного дежурного либо применит старое подавление после окончания обслуживания.

Используйте оптимистичную конкуренцию. Агент читает версию 17, предлагает подтверждение для версии 17, а шлюз выполняет его лишь тогда, когда запись поставщика по-прежнему соответствует нужному состоянию. Если другой дежурный успел изменить инцидент, верните конфликт с описанием расхождения. Не применяйте операцию к новому состоянию молча.

```json
{
  "error": "state_conflict",
  "incident_id": "inc_01JQ8K4Q6M",
  "expected_version": 17,
  "actual_version": 19,
  "actual_status": "resolved",
  "retryable": false
}
```

Не учите агента повторять любой конфликт. Сетевой тайм-аут может оправдать идемпотентный повтор с тем же идентификатором операции. Конфликт состояния требует нового чтения и обычно нового решения. Если инцидент закрыт, подтверждение уже не нужно. Если его перенаправили другой команде, исходное согласование может не распространяться на нового получателя.

Типичная ошибка начинается с медленного согласования. Агент читает оповещение triggered о задержке базы данных и просит Alice разрешить подтверждение. Пока карточка ждет, Bob устраняет влияние и закрывает инцидент. Затем Alice подтверждает устаревшую карточку. Наивный адаптер отправляет `acknowledge`, получает специфичный для поставщика успех или возвращает инцидент в активное состояние, а затем записывает Alice ответственной за завершенную работу. Привязка к версии останавливает действие до появления бессмысленной хронологии.

Идемпотентность решает другую задачу. Назначайте каждому предложенному переходу неизменный ID операции и сохраняйте результат. Если поставщик применил подтверждение, но шлюз потерял HTTP-ответ, повтор вернет сохраненный результат, а не добавит вторую запись в хронологию или новое уведомление. Контроль конкуренции защищает намерение от изменившегося состояния, а идемпотентность защищает одно намерение от двойного выполнения.

## Маршрутизации и подавлению нужны отдельные права

Маршрутизация меняет того, кто несет ответственность, а подавление меняет сигналы, создающие шум. Ни одно действие не доказывает восстановление, и ни одно нельзя прятать внутри подтверждения.

Перенаправляйте до подтверждения, если текущий сервис явно выбран ошибочно и никто еще не принял работу. После подтверждения действуйте осторожно: дежурный уже может вести расследование. Переход должен сообщать, меняется ли владелец, остается ли первоначальный дежурный подписанным и запускается ли схема эскалации получателя. Агент не должен выводить эти эффекты из названия команды.

Для подавления нужны явная область и срок окончания. Документация PagerDuty Event Management говорит, что подавленные оповещения остаются доступными для расследований, но не создают инциденты. Документация Event Orchestration также описывает маршрутизацию несовпавших событий в сервис или их подавление через общий маршрут. Это решения при приеме сигнала, а не другие названия закрытия открытого инцидента.

Документация Datadog Downtimes проводит еще одну полезную границу: период обслуживания заглушает оповещения и уведомления, но не останавливает переходы состояния монитора. Если период заканчивается, а монитор все еще сообщает об ошибке, уведомления могут возобновиться. Во время обслуживания обычно требуется именно такое поведение. Система помнит нездоровое состояние и не переписывает его как нормальное ради тишины.

Запрос подавления должен включать селектор сигнала, время начала и окончания, причину, создателя и поведение после истечения. Широкий селектор уровня целого сервиса требует более строгого согласования, чем одна группа монитора. Бессрочное подавление следует отклонять или пропускать через явный процесс исключения. Агент не должен создавать тихий сбой без ответственного.

Не включайте подавление после подтверждения автоматически лишь потому, что дежурный принял оповещение. Одни системы останавливают эскалацию, другие продолжают повторные уведомления. Google Cloud Monitoring прямо документирует, что подтверждение не прекращает повторные уведомления. Сохраняйте поведение поставщика или запрашивайте подавление отдельно, чтобы проверяющий видел причину тишины.

## Закрытие должно следовать за доказательствами

Закрывайте инцидент лишь тогда, когда доказательства восстановления удовлетворяют объявленному условию. Успешная команда исправления доказывает выполнение действия, но не восстановление сервиса.

Эта разница ловит знакомую ошибку автоматизации. Агент перезапускает процесс, получает нулевой код выхода и закрывает инцидент. Процесс запускается, не проходит проверку готовности и снова падает через тридцать секунд. Команда выполнилась успешно, но сервис так и не восстановился. Закрытие по успеху команды создает два инцидента, два оповещения и неверное время восстановления вместо одного непрерывного события.

Определяйте доказательства рядом с типом инцидента. Для сбоя доступности может потребоваться исчезновение условия оповещения на протяжении окна оценки. Для проблемы с очередью могут потребоваться объем очереди и возраст самого старого сообщения ниже порогов. Оповещение о сертификате можно закрыть после того, как развернутый endpoint покажет ожидаемый сертификат, а не после записи файла на один хост.

Агент может собрать доказательства и предложить закрытие. Шлюз должен приложить к согласованию наблюдения, их время, источник и пробелы. Если монитор по-прежнему сообщает об активном условии, отклоните закрытие. Google Cloud Monitoring следует этому правилу для метрических инцидентов: документация сообщает об ошибке `Unable to close incident with active conditions`, когда свежие данные продолжают нарушать политику.

Ручное закрытие все равно нужно. Мониторы могут запаздывать, телеметрия может сломаться, а дежурный может знать, что затронутый сервис намеренно выведен из эксплуатации. Явно фиксируйте исключение, причину и согласующего, а также сохраняйте последнее нездоровое наблюдение. Исключение должно оставаться проверяемым и не служит поводом ослаблять обычный переход.

Поведение при повторном открытии тоже входит в контракт. Укажите, открывает ли повторный сигнал тот же инцидент или создает новый, и сохраняйте идентификаторы связи в обоих случаях. Агент не должен считать, что `resolve` заглушит следующее событие. PagerDuty пишет, что закрытый инцидент можно открыть снова, если работа продолжается. Datadog указывает, что ручное закрытие монитора переводит его в OK лишь до следующей оценки. Следующая нездоровая оценка может снова вызвать оповещение.

## Журнал аудита должен сохранять решение

Журналы поставщика показывают, что учетные данные API вызвали endpoint. Им редко хватает контекста, чтобы объяснить предложение агента, решение человека и состояние, которое видел человек. Ведите отдельную запись решения и связывайте ее с событием поставщика.

Полное событие перехода содержит неизменный ID операции, хеш запроса, нормализованное действие, цель, состояния до и после, личности инициатора, согласующего и исполнителя, способ согласования, время решений, идентификатор ответа поставщика и результат. Записывайте отклоненные и истекшие предложения. Отклоненное подавление объясняет продолжение уведомлений, а истекшее согласование объясняет, почему предложенное подтверждение не выполнили.

Защитите последовательность от незаметного редактирования. Хранилище с добавлением записей, ограниченный круг авторов, правила хранения и криптографическая цепочка противостоят разным угрозам. Sallyport строит журналы Sessions и Activity из единого зашифрованного журнала с хеш-цепочкой, а `sp audit verify` проверяет цепочку шифротекста офлайн без ключа расшифровки. Интеграция получает доказательства запуска агента и каждого внешнего вызова, не раскрывая учетные данные агенту.

Не храните только текстовое объяснение агента. Модель может уверенно составить неточное резюме, поэтому рядом нужны структурированные факты. Причина вроде «оповещение о задержке принято» помогает человеку быстро читать хронологию, а ID инцидента, версия состояния, хеш HTTP-запроса и личность согласующего позволяют проверить запись.

Читателям аудита нужна стабильная семантика при развитии интеграции. Версионируйте схему событий и названия нормализованных действий. Если адаптер меняет сопоставление с поставщиком, записывайте его версию для каждого вызова. Иначе старое событие `acknowledge` станет неоднозначным после изменения побочных эффектов в новой версии.

Доступ к аудиту не должен давать доступ к учетным данным инцидента. Разделите возможность проверить порядок событий и возможность расшифровать чувствительные поля. Удаляйте секреты до попадания в запись, а не надейтесь на осторожность каждого будущего читателя.

## Проверяйте переходы как враждебные процессы

Тесты успешного пути доказывают работу endpoint в ситуации, когда ничего интересного не происходит. Автоматизацию инцидентов нужно проверять с остановками между каждым чтением, согласованием, вызовом и ответом.

Начните с пяти инвариантов:

1. Подтверждение никогда не меняет восстановление с открытого на закрытое.
2. Закрытие никогда не создает и не продлевает подавление.
3. Маршрутизация никогда не означает, что получатель подтвердил инцидент.
4. Каждое согласованное изменение называет инициатора, согласующего, исполнителя и объект.
5. Устаревшее согласование нельзя выполнить для другой версии состояния или другой цели.

Затем подключите адаптер к имитации поставщика, которая меняет состояние между вызовами. Закройте инцидент, пока подтверждение ждет согласования. Измените маршрут перед выполнением подавления. Верните тайм-аут после принятия запроса и отправьте тот же ID операции снова. Отзовите сессию после согласования, но до выполнения. Каждый случай должен давать определенный результат и событие аудита.

Проверяйте различия поставщиков, не стирайте их. Один пейджер приостанавливает эскалацию после подтверждения, другой продолжает уведомления. Нормализованный ответ может показывать `escalation_paused` и `notifications_suppressed` как отдельные факты. Не обещайте общий эффект, который адаптер не может проверить.

Проверяйте описания инструментов с той же настороженностью, что и код. Фраза «Разберись с инцидентом» предлагает модели самой выбрать результат. Фраза «Запиши, что дежурная группа Payments приняла расследование; оставь восстановление открытым» описывает ограниченный переход. Текст инструмента входит в поверхность управления, поскольку формирует запрос агента.

Наконец, проверьте отсутствие полномочий. Агент с правом подтверждения должен получить понятный отказ при попытке закрыть, перенаправить или подавить. Отказ не должен предлагать автоматический запасной путь, который выполнит другое изменение. Безопасная ошибка оставляет инцидент видимым и неизменным.

## Чем серьезнее последствия, тем уже права агента

Разрабатывайте права с учетом эффекта действия, а не удобства вызывающего процесса. Чтение инцидента, подтверждение назначенной работы, перенос ответственности, заглушение сигнала и объявление восстановления требуют все более строгих разрешений, если их последствия различаются.

Начните с возможностей, которые называют глагол и область. `incident.acknowledge` для сервиса Payments уже, чем `incident.write` для всей рабочей среды. Право маршрутизации может ограничивать получателей сервисами одной группы. Право подавления может ограничивать селекторы и длительность. Право закрытия может требовать согласованный профиль доказательств. Шлюз должен оценивать ограничения по структурированным полям запроса, а не по объяснению агента.

В право входят время и личность процесса. Сессия агента для одной задачи программирования не должна сохранять доступ к инцидентам после завершения процесса. Если человек отозвал сессию во время ожидания согласования, выполнение должно завершиться отказом, даже когда прежнее решение в тот момент было допустимым. Согласование подтверждает предложенный переход и не возвращает права инициатору, который их потерял.

Разделяйте разрешение и согласование. Разрешение отвечает, может ли инициатор пытаться выполнить этот класс действий. Согласование отвечает, можно ли сейчас выполнить конкретную попытку. Обязательное согласование не исправляет слишком широкое разрешение: проверяющие со временем начинают нажимать кнопку автоматически, особенно когда карточка скрывает область. Узкое разрешение тоже не заменяет решение человека для перехода с серьезными последствиями, если организация требует такого решения.

Строже контролируйте действия, снижающие видимость. Подтверждение добавляет владельца и оставляет сбой видимым. Маршрутизация может убрать оповещение из поля зрения текущей команды. Подавление может скрыть продолжающийся сбой от людей. Закрытие может убрать инцидент из активной очереди и изменить отчеты. Такой порядок подходит не всем, но его описание выявляет разногласия до ночного инцидента.

Учетные данные должны соблюдать те же границы. Если поставщик дает разные роли или токены, не выдавайте исполнителю учетную запись с управлением расписаниями и сервисами ради одного подтверждения. Если доступны только широкие учетные данные, ограничивайте операцию в шлюзе и явно указывайте ограничение в модели угроз. Аудит поставщика покажет потенциальные возможности учетных данных, а запись шлюза должна показать разрешенное действие в конкретном запросе.

Отзыв должен давать предсказуемый результат. Отзыв сессии блокирует все новые операции процесса. Отзыв согласования блокирует связанную операцию, если выполнение еще не началось. Отзыв права маршрутизации или подавления блокирует будущие запросы, а действующее подавление отменяется отдельным переходом. Не удаляйте незаметно доказательство прежнего решения.

Команды часто предлагают одно согласование в начале инцидента, после которого агент делает все остальное. Идея популярна, потому что повторные запросы мешают дежурным. Для действий с разными последствиями она ошибочна. Один раз разрешите сессию для обычного доступа, а отдельное согласование сохраните для широкого подавления, маршрутизации между командами и закрытия. Работа с небольшим риском продолжится, но первый поспешный клик не даст права закрыть инцидент через час.

Перед развертыванием составьте матрицу полномочий: действия в строках, области в столбцах. Для каждой ячейки решите, может ли агент читать, предлагать, выполнять без нового решения или выполнять только после согласования. Укажите максимальный срок подавления, разрешенных получателей, допустимые доказательства восстановления и поведение при отсутствии ответа. Пустая ячейка должна запрещать действие, а не наследовать право от широкой метки.

Проверьте матрицу с реальными учетными данными поставщика. Политика, которая запрещает закрытие в шлюзе, неполна, если другой доступный HTTP-инструмент позволяет агенту напрямую вызвать endpoint поставщика. Учтите все пути к пейджеру: универсальные HTTP-запросы, запуск команд, ретрансляторы webhook и сохраненные скрипты. Учетные данные для обхода шлюза не должны быть доступны процессу агента.

Для запросов согласования также нужны ограничения частоты, но они должны безопасно отказывать. Если агент заваливает проверяющего одинаковыми запросами подтверждения, объединяйте совпадающие предложения или давайте лишним истечь. Нельзя отвечать на перегрузку автоматическим согласованием, закрытием или скрытием инцидента. Записывайте лишние запросы, чтобы команда исправила породивший их цикл.

## Тихий пейджер может показывать открытый инцидент

Шум оповещений, ответственность дежурного, здоровье сервиса и маршрутизация между командами независимы. Объединение их в один статус упрощает интерфейс внешне, но переносит неоднозначность в автоматизацию, метрики и разборы.

Сохраняйте подтверждение узким, даже если агент выполняет его без ошибок. Пусть оно закрепляет работу, записывает согласовавшего человека и оставляет инцидент открытым. Если процессу также нужен новый маршрут, временное подавление или закрытие после проверенного восстановления, оформляйте каждое действие как отдельный видимый запрос и решение.

Такая схема требует нескольких дополнительных вызовов. Взамен руководитель инцидента получает хронологию, которой можно доверять в два часа ночи: кто принял оповещение, кто разрешил переход, что в тот момент показывала система и почему инцидент в итоге закрыли.
