Читать 6 мин

AI-агенты меняют feature flags: контролируйте каждую запись

AI-агентам, меняющим feature flags, нужны контролируемые записи в продакшен с явными подтверждениями, условными обновлениями, повторной проверкой состояния и надежными доказательствами для аудита.

AI-агенты меняют feature flags: контролируйте каждую запись

AI-агенты, меняющие feature flags, должны работать с ними как с записями в продакшен, потому что это и есть записи в продакшен. Флаг может находиться за пределами конвейера развертывания, но за несколько секунд он способен включить код для клиентов, отключить платежный путь, расширить эксперимент или выключить проверку безопасности.

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

Изменение флага является записью в продакшен

Обновление feature flag по своим операционным последствиям ничем не отличается от изменения настройки продакшен-базы данных или редактирования правила маршрутизации в рабочей системе. Вызов API может быть небольшим, но эффект способен оказаться широким и мгновенным.

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

В статье Martin Fowler о Feature Toggles есть различие, которое команды часто упрощают до одного понятия. Переключатели релизов, экспериментов, операционного управления и прав доступа живут разное время и меняются с разной частотой. Это различие должно влиять на контроль действий агента. Операционный переключатель, отключающий неисправную интеграцию, может требовать быстрого подтверждения человека. Переключатель прав доступа, меняющий круг пользователей с доступом к регулируемым данным, заслуживает гораздо более строгого процесса. Слово «флаг» почти ничего не говорит о риске.

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

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

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

Разделяйте намерение, авторизацию, выполнение и наблюдаемое состояние

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

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

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

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

Наблюдаемое состояние получают, повторно читая флаг после записи. Так обнаруживаются неверные данные, частичные обновления, поведение по умолчанию и вызовы, отправленные не в тот проект или окружение. Повторное чтение тоже имеет ограничения. Кэшированные SDK-клиенты могли еще не получить измененную конфигурацию, а само чтение не доказывает, что код за флагом работает правильно. Это отдельные наблюдения для телеметрии развертывания и мониторинга приложения.

Это различие особенно важно при откате. Допустим, агент запрашивает checkout_v2=false, человек подтверждает запрос, а провайдер возвращает успех. Если до повторного чтения другой оператор меняет флаг, простой журнал расскажет стройную, но ложную историю. Правильная запись говорит, что разрешенный запрос успешно прошел границу API, а затем показывает наблюдаемое состояние, включая версию или ревизию, если провайдер ее предоставляет.

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

Фиксируйте конверт мутации до вызова провайдера

Агент должен отправлять структурированный запрос на изменение, а не составлять произвольный HTTP-запрос к провайдеру флагов. Фиксированный конверт понятен проверяющему и поддается проверке в шлюзе.

В примере используется Boolean-флаг, но та же форма подходит для JSON-конфигурации, процентных раскаток и правил таргетинга. Изменения правил нужно отделять от изменений скалярного значения. Правило таргетинга может изменить охват намного сильнее, чем предполагает простое значение true или false.

{
  "request_id": "ffchg_01J8KQ4W6D7P",
  "correlation_id": "incident_INC-1842",
  "operation": "set_boolean_flag",
  "flag": {
    "project": "storefront",
    "environment": "production",
    "name": "checkout_v2"
  },
  "expected": {
    "value": true,
    "revision": "481"
  },
  "requested": {
    "value": false
  },
  "reason": "Reduce checkout failures while payment timeout is investigated",
  "rollback": {
    "value": true,
    "expires_at": "2025-03-08T18:00:00Z"
  }
}

Блок expected предотвращает незаметную перезапись. Он означает: выполнить мутацию только если текущее значение и ревизия все еще совпадают с тем, что проверил инициатор. Если после чтения агентом флаг изменил человек или автоматизация, запрос нужно отклонить и показать новое состояние. Слепой повторный запуск здесь не подходит. Агент должен запросить подтверждение заново, потому что основание для действия исчезло.

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

Шлюз может возвращать результат в таком виде:

{
  "request_id": "ffchg_01J8KQ4W6D7P",
  "status": "applied",
  "provider_request_id": "p_9d3ab",
  "authorization": {
    "approver": "[email protected]",
    "approved_at": "2025-03-08T17:18:32Z"
  },
  "observed": {
    "value": false,
    "revision": "482",
    "read_at": "2025-03-08T17:18:35Z"
  }
}

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

Подтверждение должно описывать радиус воздействия

Человек не может безопасно подтвердить изменение, зная только имя флага. Названия меняются, флаги переживают первоначальное назначение, а Boolean может скрывать большое правило таргетинга за безобидной подписью.

На карточке подтверждения или экране проверки нужно показывать текущее представление рядом с запрошенным. Для процентной раскатки укажите точные старый и новый проценты, аудиторию или сегмент, зависимый флаг, если он есть, и окружение. Для изменения правила покажите полное правило до и после в понятном каноническом виде. Если в diff пропустить условие, потому что оно кажется повторяющимся, кто-то легко превратит «сотрудники из региона A» в «все пользователи».

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

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

Я бы требовал отдельного подтверждения для каждой мутации в продакшене при любом из условий:

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

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

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

Параллельные изменения делают автоматический откат небезопасным по умолчанию

Поставьте шлюз перед флагами
Подключайте агента с поддержкой MCP через sp mcp и храните его HTTP-учетные данные на управляющем Mac.

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

Представим последовательность. В 10:00 текущее значение равно true, ревизия 481. Агент получает разрешение установить false, и провайдер создает ревизию 482. В 10:06 дежурный инженер видит другой симптом и намеренно устанавливает true, ревизию 483. В 10:08 условие мониторинга агента срабатывает, и он выполняет запланированный откат к true.

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

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

Используйте запрос на откат, связанный с исходным действием:

{
  "request_id": "ffrb_01J8KR0Y8J2M",
  "operation": "rollback_boolean_flag",
  "parent_request_id": "ffchg_01J8KQ4W6D7P",
  "flag": {
    "project": "storefront",
    "environment": "production",
    "name": "checkout_v2"
  },
  "expected": {
    "value": false,
    "revision": "482"
  },
  "requested": {
    "value": true
  }
}

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

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

Ограничьте операции, цели и учетные данные

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

Начните со списка разрешенных операций. get_flag и list_flag_metadata только читают данные. set_boolean_flag выполняет узкую запись. set_rollout_percentage, replace_targeting_rule, create_flag, archive_flag и edit_segment имеют гораздо более серьезные последствия и должны быть отдельными операциями. Не открывайте обобщенное действие PATCH /flags/{id}, рассчитывая, что инструкции удержат агента в безопасных рамках. Универсальные patch-операции позволяют передавать поля, которых никто из проверяющих не ожидал.

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

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

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

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

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

Проверяйте контур контроля на сбоях, а не только в штатном сценарии

Держите каждый вызов флага на виду
Sallyport записывает отдельные HTTP-вызовы в журнал Activity, отдельно от запустившего их сеанса агента.

Интеграция feature flags готова только после проверки поведения при нарушении ее предположений. Штатный сценарий «прочитать значение, подтвердить, обновить» почти ничего не доказывает.

Проведите контролируемую проверку в нерабочем окружении и намеренно вызовите такие ситуации:

  1. Измените флаг после того, как агент прочитал его, затем отправьте исходный запрос. Шлюз должен отклонить устаревшую ожидаемую ревизию.
  2. Отправьте один и тот же идентификатор запроса дважды после имитации потери ответа. Второй вызов должен вернуть первый записанный результат, а не выполнить новую мутацию.
  3. Отклоните подтверждение. Провайдер не должен получить запись, а аудит должен показать отказ, а не неоднозначный тайм-аут.
  4. Пусть человек изменит флаг после действия агента, затем запустите автоматический откат. Откат должен остановиться и перейти на проверку.
  5. Заблокируйте или отзовите сеанс агента во время ожидающего запроса. Действие должно завершиться ошибкой до использования учетных данных.

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

Проверяйте и канонизацию. Два JSON-правила таргетинга могут означать одно и то же, но содержать поля в разном порядке. Если compare-and-set сравнивает исходный JSON, появятся ложные конфликты. Если нормализация слишком агрессивна, можно пропустить смысловое различие. Выберите каноническое представление модели провайдера, записывайте его и проверяйте поля в другом порядке, пропущенные значения по умолчанию и эквивалентные ссылки на сегменты.

Наконец, проверьте сценарий, в котором провайдер возвращает успех, но повторное чтение не удается. Запишите execution=accepted и observed=unknown, не помечайте весь запрос как успешный. Кто-то должен проверить состояние провайдера до того, как агент выполнит зависимое изменение.

Аудит должен выдержать спорный инцидент

Храните токены флагов вне агентов
Sallyport хранит учетные данные провайдера флагов в зашифрованном хранилище и сам выполняет HTTP-запрос.

Полезная запись изменения feature flag должна отвечать на скептический вопрос: «Откуда мы знаем, что эту историю не отредактировали задним числом?» Обычных журналов приложения часто достаточно для отладки, но они редко отвечают на этот вопрос, если к системе журналирования имеют доступ многие люди.

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

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

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

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

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

Сначала поручите агенту подготовить предложение об изменении

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

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

Не требуйте длинного эссе. Требуйте полный запрос. Разница важна. Многословное описание часто скрывает, что агент не проверил целевое окружение или не получил текущее правило. Структурированный конверт сразу показывает пропуск.

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

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

Вопросы и ответы

Можно ли разрешить AI-агенту менять feature flags в продакшене?

Изменение feature flag меняет поведение для реальных пользователей, даже если код не разворачивается. Относитесь к нему как к записи в продакшен-конфигурацию: укажите цель, запишите запрошенное значение, предусмотрите ответственное подтверждение и проверьте итоговое состояние.

Так ли опасно чтение feature flags, как их изменение?

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

Что должен содержать аудит-журнал изменения feature flag агентом?

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

Доказывает ли успешный ответ API, что изменение флага сработало?

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

Когда для каждого изменения флага с помощью AI нужно отдельное подтверждение?

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

Как ограничить права агента на работу с feature flags?

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

Может ли AI-агент откатить собственное изменение feature flag?

Да, но только если откат был заранее описан и проверяется относительно состояния, которое агент действительно изменил. Слепое восстановление старого значения может перезаписать более позднее изменение человека, поэтому откату нужна проверка версии или условие compare-and-set.

Почему встроенной истории аудита платформы флагов недостаточно?

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

Как связать изменение флага агентом с инцидентом или развертыванием?

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

Как безопаснее всего дать AI-агенту для программирования доступ к API feature flags?

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

Sallyport

Sallyport выполняет API-вызовы и SSH-команды за вашего ИИ-агента. Ключи остаются в локальном хранилище на вашем Mac; вы подтверждаете каждый запуск, и каждое действие попадает в запечатанный журнал.

© 2026 Sallyport · Открытый код по лицензии Apache-2.0 · Oleg Sotnikov