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

Порядок действий агента определяет, объясняет ли отчет об инциденте, что произошло, или просто показывает набор временных меток. Когда автономный агент программирования может вызывать API и открывать SSH-сессии, расследованию нужно установить, какой процесс действовал, что он пытался сделать, что завершилось и какой результат получил агент до выбора следующего действия.
Списка, отсортированного по времени, недостаточно. Часы расходятся, запросы выполняются одновременно, ответы приходят не по порядку, а тайм-аут может скрыть действие, которое на удаленной стороне все же завершилось успешно. Создавайте записи, сохраняющие контекст сессии, надежный локальный порядок и отдельные временные метки этапов жизненного цикла. Иначе первый серьезный инцидент превратит журнал аудита в спор о догадках.
Одного времени недостаточно, чтобы установить порядок действий
Метка времени показывает, когда событие заметили одни часы. Она не доказывает, что событие произошло раньше любого другого события с более поздней меткой. Это кажется теорией, пока два вызова не покидают агента почти одновременно, один удаленный сервис не начинает отвечать медленно, а второй вызов не возвращается первым. Сортировка по completed_at показывает порядок ответов, а не порядок решений агента.
У каждого вызова есть несколько важных моментов. Агент решает вызвать инструмент. Шлюз принимает запрос и проверяет его разрешение. Затем он передает работу HTTP-сервису или SSH-помощнику. Удаленная сторона может принять запрос. Возвращается ответ. Шлюз передает результат агенту. Если считать все это одним событием, исчезают доказательства, нужные для объяснения сбоя.
Храните локальный монотонно возрастающий call_sequence в каждой сессии. Назначайте его, когда шлюз принимает вызов, до начала сетевой работы. Это число отвечает на ограниченный, но полезный вопрос: «В каком порядке этот шлюз принял вызовы от данного процесса агента?» Оно не утверждает, что описывает порядок выполнения на удаленной стороне. Четко обозначенная область действия лучше широкого заявления, которое невозможно защитить доказательствами.
Для самого журнала аудита используйте вторую постоянную последовательность. Вызовы разных сессий могут пересекаться по времени, а события авторизации, отзыва, блокировки vault и проверки должны находиться в одном потоке доказательств. Последовательность журнала показывает порядок записи сборщиком. Последовательность вызовов сессии показывает порядок намерений в одном запуске агента. Ни одно из этих полей не заменяет другое.
Не подменяйте номера последовательности точностью времени. Дополнительные знаки после запятой лишь точнее записывают показания часов. Они не устраняют корректировку часов и не устанавливают общий порядок для параллельных записывающих процессов.
RFC 3339 задает удобный совместимый формат для календарных временных меток, включая явное смещение UTC. Для экспорта и просмотра человеком используйте его форму UTC, например 2025-03-08T21:14:03.482Z. RFC 3339 не обещает причинно-следственный порядок. За него отвечает ваш сборщик, а для этого нужны поля последовательности и четкие границы событий.
Сессия должна идентифицировать действующий процесс, а не расплывчатую задачу
Сессия должна связывать упорядоченный запуск с конкретным процессом агента, получившим полномочия на действия. Она начинается, когда процесс устанавливает соединение, и заканчивается, когда процесс завершается, теряет канал или оператор отзывает его полномочия. Не определяйте сессию как «работу над задачей 184» или «дневное развертывание». Такие ярлыки помогают искать записи, но не определяют границу выполнения.
В записи сессии должно быть достаточно данных, чтобы ответить на реальные вопросы расследования: какой исполняемый файл подключился, кто его подписал, какой локальный пользователь его запустил, какой транспорт установил соединение и когда начались и закончились его полномочия. Записывайте идентификаторы, которые может подтвердить операционная система или соединение. Не позволяйте агенту записывать собственные заявления о личности в авторитетные поля.
Это особенно важно, когда кто-то переносит конфигурацию инструмента в другой процесс. В запросе действия может быть указано, что агент собирается работать с определенным репозиторием. Шлюз должен записать личность процесса, которую он наблюдал. Во время инцидента второе утверждение весит больше.
Практическая запись сессии может выглядеть так:
{
"event_id": "01JNRQ2Q9Y9J0R3E5P8F7K2X4M",
"journal_sequence": 8124,
"event_type": "session.opened",
"occurred_at": "2025-03-08T21:14:02.901Z",
"session_id": "sess_7f31c4",
"process": {
"pid": 48102,
"code_signing_authority": "observed signing authority",
"local_user": "developer account"
}
}
Агент должен получать непрозрачный дескриптор сессии, а не право выбирать идентификатор сессии или менять ее метаданные. При этом агент может добавлять собственную метку запуска, путь к репозиторию или ссылку на задачу в отдельном поле заявленного контекста. Помечайте такие значения как предоставленные агентом. Метка может объяснить намерение, но не должна переопределять наблюдаемые факты о процессе.
Авторизация на уровне сессии дает еще одно преимущество для расследования. Она фиксирует решение человека, связанное с ограниченным запуском процесса. Если этот запуск позже выполнит опасный вызов, проверяющие увидят событие авторизации, которое ему предшествовало, и событие закрытия или отзыва, которым запуск завершился. Одобрение, молча распространяющееся на последующие процессы, создает пробел, который не исправит никакое количество записей о вызовах.
Для одного вызова нужен жизненный цикл, а не одна строка о завершении
Хорошая запись вызова сохраняет жизненный цикл одной попытки. Она не сводит предпринятый запрос, сетевую отправку, удаленный результат и результат, видимый агенту, к одному расплывчатому полю «успех» или «ошибка».
Начните с неизменяемого call_id и следующего call_sequence сессии. Запишите событие принятия до обращения во внешний мир. Если политика или одобрение блокирует запрос, события принятия и отказа все равно важны. Они показывают намерение и работу контроля, не создавая видимость внешнего действия.
Для разрешенного HTTP-действия зафиксируйте отдельные границы событий:
call.acceptedзаписывает упорядоченный запрос на шлюзе.call.authorizedилиcall.deniedзаписывает решение контроля.call.dispatchedпоказывает, что шлюз передал запрос сетевому клиенту.call.result_receivedпоказывает транспортный итог или ответ удаленной стороны.call.result_returnedпоказывает результат, возвращенный агенту.
Названия могут отличаться, но смысл должен сохраняться. Полученный результат не всегда возвращается агенту. Шлюз может удалить часть ответа, отклонить некорректные данные, потерять соединение с агентом или столкнуться с внутренней ошибкой при подготовке результата. Расследованию нужно видеть этот разрыв.
Сохраняйте request_started_at, dispatched_at, result_received_at и result_returned_at, когда соответствующие моменты происходят. Для не наступившего момента используйте null. Не придумывайте время завершения, если процесс аварийно завершился. Запишите более позднее событие восстановления, указывающее, что сборщик обнаружил незавершенный вызов.
Пример показывает структуру завершенного запроса без токена bearer и полного тела ответа:
{
"event_id": "01JNRQ3M8W7P0Q4R6S9T1V2X3Y",
"journal_sequence": 8131,
"event_type": "call.result_received",
"occurred_at": "2025-03-08T21:14:05.841Z",
"session_id": "sess_7f31c4",
"call_id": "call_00017",
"call_sequence": 17,
"channel": "http",
"target": "api.internal.example/v1/releases",
"method": "POST",
"dispatch_event_id": "01JNRQ3G2A...",
"outcome": {
"transport": "response",
"http_status": 201,
"response_digest": "sha256:..."
}
}
Дайджесты запроса и ответа позволяют сопоставлять сохраненные доказательства, не передавая секреты или большие чувствительные данные каждому читателю журнала. Дайджест не делает секрет безопасным для записи. Значения с низкой энтропией, предсказуемые идентификаторы и короткие токены по-прежнему можно угадать. Исключайте учетные данные во время сбора, а затем решайте, какие фрагменты данных действительно нужны процессу расследования.
Повторы и тайм-ауты создают самую сложную неопределенность
Тайм-аут означает, что вы не знаете, действовала ли удаленная сторона. Он не означает, что удаленная сторона ничего не сделала. Команды часто ошибаются здесь, потому что прикладные журналы считают тайм-аут простой ошибкой, а следующую попытку рассматривают как замену первой.
Представьте агента, создающего релиз HTTP-запросом. Вызов 41 после отправки получает тайм-аут запроса. Агент видит ошибку и отправляет вызов 42, повторную попытку. Позже удаленный сервис обрабатывает оба запроса. Если журнал заменил вызов 41 итоговым статусом «повтор», расследование увидит один успешный запрос и пропустит дублирующее действие.
Каждой сетевой попытке нужны собственные call_id и call_sequence. Добавляйте retry_of, когда попытка напрямую следует за предыдущей. Сохраняйте причину повтора, которую видел агент: тайм-аут, сброс соединения или полученный статус, допускающий повтор. Такая связь позволяет проследить цепочку и не сворачивать ее в одну запись.
Полная последовательность может выглядеть так:
sequence 41 accepted 21:14:11.024Z create release, request r_8d2
sequence 41 dispatched 21:14:11.027Z
sequence 41 result_received 21:14:41.031Z timeout
sequence 41 result_returned 21:14:41.034Z timeout returned to agent
sequence 42 accepted 21:14:42.112Z retry_of call_00041, request r_8d2
sequence 42 dispatched 21:14:42.115Z
sequence 42 result_received 21:14:42.490Z HTTP 201
sequence 42 result_returned 21:14:42.493Z HTTP 201 returned to agent
Повторная ссылка на запрос полезна только при наличии у удаленного API механизма идемпотентности или другого постоянного идентификатора операции. Если сервис принимает ключ идемпотентности, создайте и запишите несекретный ключ, неизменный для одной предполагаемой операции во всех повторах. Если такого механизма нет, укажите, что риск повтора остается нерешенным. Не объявляйте операцию идемпотентной только потому, что данные выглядят одинаково.
SSH создает другую проблему. Команда может выполниться удаленно, а соединение оборваться до того, как клиент получит вывод или код возврата. Записывайте отправку команды, идентификатор соединения, ссылку на хост и наблюдаемое состояние завершения. Прерванную SSH-команду помечайте как «результат неизвестен», а не как «ошибка». Поздняя команда, проверяющая состояние на удаленной стороне, может уменьшить неопределенность, но не переписывает исходный результат.
Не превращайте все ошибки в терминальные события. Отказ в авторизации завершает этот вызов, поскольку внешней отправки не было. Локальная ошибка DNS может быть окончательной для попытки. Тайм-аут после выхода байтов из машины оставляет внешний результат неизвестным. Эти категории требуют разных решений при расследовании.
Записывайте два вида времени и объясняйте их ограничения
Обычное время делает хронологию понятной при сопоставлении разных систем. Монотонное время измеряет прошедший интервал без влияния сетевой синхронизации или ручной корректировки часов. Собирайте оба значения, если операционная система их предоставляет, и укажите в схеме смысл каждого.
Для каждого события журнала записывайте RFC 3339 UTC occurred_at. Для событий внутри активной сессии также записывайте monotonic_ns, измеренное от выбранного процессом начала монотонных часов. Не сравнивайте монотонные показания разных машин, если специально не установили общую точку отсчета. Это локальные измерения.
Коррекция часов может создать такую путаницу:
journal 901 wall 21:19:07.900Z monotonic 5562019921 call accepted
journal 902 wall 21:18:58.104Z monotonic 5562026310 call dispatched
Обычные часы пошли назад. Последовательность журнала и монотонное значение по-прежнему показывают, что отправка последовала за принятием. Экспорт должен сохранять исходные временные метки, а не молча сортировать и переписывать их. Добавьте событие сборщика, когда операционная система сообщает о существенном изменении времени, если это можно наблюдать. Оно даст проверяющим объяснение расхождения.
NIST Special Publication 800-92, Guide to Computer Security Log Management, рекомендует синхронизировать часы и определить требования к данным журнала до инцидента. Это правильная рекомендация, но синхронизация часов сама по себе не устанавливает порядок внутри запуска агента. Она улучшает сопоставление с удаленным API, CI-сервисом или журналами хоста. Локальная последовательность по-прежнему устанавливает порядок сборщика.
Удаленные временные метки храните в отдельных полях. HTTP-заголовок Date, идентификатор запроса провайдера и время события, созданное сервером, являются внешними утверждениями. Сохраняйте их источник и точное значение. Не копируйте их в occurred_at и не используйте для перенумерации локального журнала. Удаленная метка может помочь позже согласовать системы, но она может отражать очередь, другие часы или момент создания ответа.
Для полей длительности тоже нужно точное определение. gateway_duration_ms может означать время от принятия до возврата результата. network_duration_ms может означать время от отправки до получения результата. Запишите определение рядом со схемой. Иначе отчет о том, что вызов длился 30 секунд, не объяснит, произошла ли задержка до отправки, на удаленном сервисе или после возврата ответа.
Сборщик аудита должен выбрать порядок до публикации результатов
Невозможно восстановить порядок, если параллельные рабочие процессы записывают данные по мере завершения. Дайте сборщику аудита один путь добавления, который назначает последовательность журнала, фиксирует время события, связывает предыдущую запись и сохраняет запись до того, как система сообщит агенту о внешне значимом изменении состояния.
Для этого не нужен один большой блокировщик вокруг всей сетевой работы. Вызовы могут выполняться параллельно. Сборщику нужна лишь узкая сериализованная точка фиксации. Когда рабочий процесс доходит до границы события, он передает событие этому сборщику. Сборщик назначает следующую постоянную последовательность журнала. Получившийся порядок отражает порядок фиксации, и именно так его нужно называть в документации и экспорте.
Типичная проблема выглядит так. Рабочий процесс A принимает вызов 17 и начинает медленный запрос. Рабочий процесс B принимает вызов 18 и быстро завершается. Если процессы добавляют только записи о завершении, журнал начинается с успеха вызова 18. Расследование не может понять, выполнялся ли вызов 17, не был ли отправлен или был пропущен. События принятия и отправки вызова 17 закрывают этот пробел.
Цепочка хешей добавляет доказательство неизменности к зафиксированной последовательности. Каждая запись содержит дайджест предыдущей зафиксированной записи и дайджест собственных канонических данных. Канонизация важна: одинаковые данные должны давать одинаковые байты до хеширования. Укажите порядок полей, кодировку UTF-8, представление времени, обработку null и форматы чисел. Фраза «мы хешируем JSON» не является спецификацией, потому что обычный порядок объектов JSON не относится к свойствам безопасности.
Концептуальная запись может содержать такие поля:
{
"journal_sequence": 8131,
"event_id": "01JNRQ3M8W7P0Q4R6S9T1V2X3Y",
"previous_hash": "sha256:9c7d...",
"record_hash": "sha256:04b1...",
"payload": {"event_type": "call.result_received"}
}
Корректная цепочка показывает, что сохраненные записи связаны без незаметного изменения, если проверяющий располагает ожидаемым началом цепочки. Она не доказывает полноту, если злоумышленник контролирует сборщик и может не дать ему записать событие. Не представляйте цепочку хешей как магию. Она делает изменение заметным, но не может записать событие, которого сборщик никогда не наблюдал.
Sallyport строит журналы Sessions и Activity из одного зашифрованного журнала аудита с цепочкой хешей. Команда sp audit verify проверяет цепочку офлайн поверх шифротекста, без ключа vault. Благодаря этому представление сессии и представление отдельных вызовов связаны с одним упорядоченным источником, а расследованию не приходится сопоставлять два разных журнала.
Создавайте хронологию, сохраняющую неопределенность
В хронологии инцидента нужно отдельно показывать факты, наблюдения и нерешенные результаты. Гладкий рассказ, превращающий неизвестное в уверенные глаголы, может казаться полезным во время напряженного разбора, но создает ложную запись, которой позже могут противоречить новые доказательства.
Предположим, процесс агента получил одобрение в 09:00:00. В 09:03:14 он отправил SSH-команду. В 09:03:16 клиент потерял соединение. В 09:03:18 агент через HTTP запросил состояние целевой системы и обнаружил измененную конфигурацию. Эти данные допускают несколько объяснений: SSH-команда завершилась, состояние изменил другой участник или сработала ранее поставленная в очередь задача. В хронологии нужно указать, какой вывод подтверждают доказательства, а какой нет.
Используйте в заметках расследования такой формат:
| Порядок | Время | Доказательство | Подтверждаемое утверждение |
|---|---|---|---|
| 444 | 09:03:14.120Z | call.dispatched | Шлюз передал SSH-команду помощнику. |
| 445 | 09:03:16.202Z | разрыв транспорта | Шлюз не получил код возврата. |
| 446 | 09:03:18.810Z | ответ на HTTP-запрос | В этот момент запрошенная конфигурация отличалась. |
| 447 | 09:03:19.001Z | call.result_returned | Агент получил результат запроса. |
Не пишите «SSH-команда изменила конфигурацию», если у вас нет прямого доказательства, связывающего команду с удаленным эффектом. Такое связывание могут дать удаленные записи аудита, уникальный идентификатор операции или ответ с постоянным идентификатором запроса на сервере. Близкая временная метка сама по себе этого не доказывает.
Расследованию также нужно знать, что видел агент, принимая последующие решения. Поэтому result_returned заслуживает отдельного события. Если удаленный ответ пришел, но агент отключился до его получения, последующее действие агента не могло быть реакцией на этот ответ. Если ответ достиг агента, он может объяснить опасную ветку его поведения.
Показывайте в представлении инцидента отдельную дорожку сессии и дорожку вызовов. На дорожке сессии отображаются события открытия, одобрения, отзыва, блокировки и закрытия. На дорожке вызовов показываются принятие, авторизация, отправка и результат. Плоский список остается доступным для проверки, но два представления отвечают на разные вопросы и не смешивают их.
Работа с секретами должна выдержать расследование
Журналы аудита часто подводят именно в момент, когда становятся особенно полезными: кто-то хочет записать все заголовки, переменные окружения оболочки и тела ответов «только для этого расследования». Такое решение может превратить локальный инцидент с агентом в утечку учетных данных.
Записывайте идентичность действия без секретных данных. Для HTTP сохраняйте метод, нормализованные хост и путь, ссылку на учетные данные или метку ключа, безопасные имена заголовков, дайджест запроса, статус ответа, идентификатор запроса провайдера, если он есть, и тщательно выбранную сводку ответа. Никогда не записывайте заголовок авторизации, исходный ключ API, закрытый ключ или полный дамп окружения.\n Для SSH записывайте ссылку на хост, ссылку на учетную запись, если это разрешено политикой, нормализованное представление команды, дайджест команды, состояние соединения и код возврата, если он получен. Сами команды могут содержать секреты. Если рабочий процесс допускает произвольный текст оболочки, используйте защищенное хранилище доказательств для строго разрешенного просмотра или сохраняйте только редактированную форму вместе с дайджестом. Не считайте журнал команд безопасным только потому, что в нем нет паролей.
Sallyport хранит API- и SSH-учетные данные в зашифрованном vault и выполняет внешнее действие, не передавая эти данные агенту. Это устраняет одну распространенную причину превращения расшифровки агента и журналов в дамп секретов, но цель, тело запроса, аргументы команды и ответ все равно могут быть чувствительными.
Разделяйте доступ к исходным записям и проверку. Ответственнику может потребоваться проверить цепочку, не имея права читать зашифрованные сведения о вызовах. Специалисту по безопасности могут быть нужны метаданные сессии и цели, но не данные полезной нагрузки. Такое разделение уменьшает зависимость расследования от копирования всего журнала в чат, тикеты или таблицы.
При экспорте доказательств включайте версию схемы, время экспорта, диапазон последовательностей журнала, результат проверки и примененные правила редактирования. Исходный защищенный журнал храните в обычном режиме. Экспорт это рабочая копия, а не замена исходным доказательствам.
Проверяйте запись на специально запутанном запуске
Демонстрация успешного сценария почти ничего не говорит о восстановлении инцидента. Проверяйте условия, делающие порядок неоднозначным: параллельные вызовы, задержанные ответы, изменения часов, завершение процессов, отказы, отзывы и тайм-аут с последующим повтором.
Проведите контролируемое упражнение с двумя разрешенными внешними целями. Пусть первый вызов подождет перед возвратом ответа. Запустите второй после отправки первого. Прервите третий после отправки. Затем отзовите сессию и проверьте, что последующие вызовы получают отказ. Экспортируйте журнал и передайте его коллеге, который не создавал сценарий.
Попросите его ответить по одному только экспорту на пять вопросов:
- Какой процесс получил полномочия и когда они закончились?
- В каком порядке шлюз принимал вызовы в этой сессии?
- Какие вызовы достигли границы отправки?
- Какой результат получил агент перед каждым последующим вызовом?
- Какие результаты остаются неизвестными, а не считаются ошибочными или успешными?
Если ему приходится спрашивать значение поля, исправьте схему или документацию экспорта. Если он делает вывод об удаленном эффекте по тайм-ауту, исправьте метки результата. Если он не может отличить повтор от новой операции, добавьте связь и идентификатор операции.
Сохраняйте материалы упражнения. Они станут регрессионными тестами при изменении клиентской библиотеки, добавлении параллельности, настройке хранения или подключении нового канала. Ошибки порядка часто появляются из-за безобидных рефакторингов: разработчики проверяют, работают ли действия, а путь доказательств незаметно меняет момент фиксации.
Инцидент не будет ждать более аккуратной системы журналирования. Назначайте последовательность сессии при принятии вызова, фиксируйте события жизненного цикла через одного упорядоченного сборщика, сохраняйте обычное и монотонное время и оставляйте неизвестные результаты неизвестными. Так у расследования появится последовательность, которую можно защитить доказательствами, а не хронология, которую приходится оправдывать.
Вопросы и ответы
Достаточно ли метки времени, чтобы восстановить инцидент с AI-агентом?
Метка времени показывает, что одни часы зафиксировали в определенный момент на одной границе события. Последовательность событий показывает порядок, в котором ваш сборщик принял или записал события. Нужны оба вида данных: время помогает понять последовательность, а поле последовательности разрешает совпадения, исправления часов и параллельную работу.
Что считать сессией агента?
Используйте одну сессию для одного запуска процесса агента, а не для репозитория, человека или календарного дня. Граница процесса помогает выяснить, какой исполняемый файл получил одобрение, когда его полномочия закончились и какие вызовы относятся к тому же запуску. Долгая сессия скрывает слишком много несвязанных действий.
Какие поля нужны в записи аудита действия агента?
Записывайте как минимум идентификатор сессии, монотонную последовательность вызовов, постоянный идентификатор события, время начала запроса, время отправки, время получения результата, время возврата результата, канал, цель и итог. Добавляйте безопасное описание запроса и результата, но исключайте учетные данные и ненужные чувствительные данные ответа.
Совпадает ли порядок запросов с порядком их обработки удаленным API?
Нет. Запрос может прийти на удаленный сервис после другого запроса, который агент отправил позже, особенно при использовании разных соединений, повторных попыток, очередей или протоколов. Сохраняйте локальный порядок отправки и любые доступные сведения о получении или завершении запроса на удаленной стороне.
Как обрабатывать повторы и тайм-ауты в журналах аудита?
У каждой повторной попытки должны быть собственные идентификатор вызова и позиция в последовательности, а также ссылка на предыдущую попытку. Если перезаписать первую попытку, невозможно понять, не удалось ли доставить первый запрос, истекло ли ожидание после доставки или запрос успел вызвать эффект до повторной попытки.
Что использовать в журнале аудита: обычное или монотонное время?
Используйте время по обычным часам для сопоставления событий человеком, а монотонное время или постоянную последовательность для локального порядка. Обычные часы могут сдвинуться при синхронизации, выходе из сна или ручной корректировке. Монотонное время не показывает календарную дату, зато сохраняет порядок интервалов в течение жизни процесса.
Может ли журнал аудита с цепочкой хешей доказать, что ни одно действие не пропущено?
Цепочка хешей показывает, что сохраненная последовательность не была незаметно изменена, если проверка выполняется относительно ожидаемого состояния цепочки. Она не доказывает, что скомпрометированный сборщик не пропустил событие до его записи. Защиту от изменения и полноту нужно считать разными свойствами.
Можно ли исправить запись аудита после ее сохранения?
Не переписывайте старое событие. Добавьте событие исправления, в котором указаны идентификатор исходного события, измененное поле, причина изменения, автор исправления и время. Удаление или редактирование исходной записи уничтожает историю, необходимую для расследования.
Как долго хранить журналы активности AI-агентов?
Храните исходные данные столько, сколько требуют расследования, юридические и операционные процессы, а затем оставляйте проверенный экспорт или сводку, если полные данные содержат чувствительную информацию. Хранение без контроля доступа создает еще один путь для утечки. Правила удаления нужно определить до инцидента, а не во время спора об очистке диска.
Как проверить, пригоден ли журнал аудита агента для расследования?
Начните с одного контролируемого запуска агента, в котором будут два перекрывающихся внешних вызова, один отложенный ответ и один повтор. Затем попросите человека, не участвовавшего в создании теста, восстановить порядок только по экспорту журнала. Если для понимания событий ему нужны устные пояснения, запись неполна.