# Agentes de IA que cambian feature flags: controla cada escritura

Los agentes de IA que cambian feature flags deben tratarse como escrituras en producción, porque eso es exactamente lo que hacen. Un flag puede estar fuera del proceso de despliegue, pero en cuestión de segundos puede activar código para los clientes, bloquear una ruta de pago, ampliar un experimento o desactivar un control de seguridad.

El error que sigo viendo consiste en dar acceso a un agente al proveedor de flags porque la tarea parece inofensiva: «activa el nuevo flujo para los usuarios internos» o «reduce el despliegue a cero». El cambio puede ser correcto. Lo peligroso es que falte el registro. Después de una interrupción, el equipo necesita saber qué solicitó el agente, quién aceptó la solicitud, qué hizo el proveedor y si el estado final coincidió con lo pedido. Una transcripción de chat no puede asumir esa responsabilidad.

## Una mutación de un flag es una escritura en producción

Una actualización de un feature flag tiene el mismo carácter operativo que cambiar un ajuste de una base de datos de producción o editar una regla de enrutamiento activa. La llamada a la API puede ser pequeña, pero el efecto puede ser amplio e inmediato.

Tratar los flags como una configuración inofensiva produce un fallo conocido. Un agente investiga un aumento de la tasa de errores, encuentra un flag asociado a la funcionalidad reciente y lo establece en `false`. Eso puede proteger a los usuarios. También puede desactivar una ruta de código no relacionada porque el flag usa una regla de segmentación en lugar de un booleano simple, o porque el agente seleccionó el entorno equivocado. Si nadie puede identificar la mutación exacta solicitada y a la persona que la aprobó, el equipo pasa el incidente discutiendo el historial en lugar de restaurar el servicio.

El artículo de Martin Fowler sobre Feature Toggles establece una distinción que los equipos suelen perder. Los toggles de lanzamiento, de experimentación, operativos y de permisos tienen vidas útiles y niveles de dinamismo diferentes. Esa distinción debería cambiar los controles aplicados a una acción de un agente. Un toggle operativo que desactiva una integración fallida puede requerir una aprobación humana rápida. Un toggle de permisos que cambia quién puede acceder a datos regulados merece un proceso mucho más estricto. Llamar «flag» a ambos dice muy poco sobre el riesgo.

Los cambios de flags también evitan controles que los ingenieros asocian con los despliegues de código. Una pull request puede mostrar revisión por pares, una compilación puede mostrar resultados de pruebas y un lanzamiento puede mostrar la versión del artefacto. Una llamada al proveedor de flags quizá solo muestre el nombre de un token y una marca de tiempo. Si un proceso autónomo controla el token, incluso ese nombre puede compartirse entre muchas ejecuciones.

Usa la misma pregunta que harías antes de cualquier escritura en producción: ¿qué estado exacto cambiará esta solicitud, bajo qué autoridad y cómo demostraremos el estado resultante?

Una lectura es diferente. Un agente puede inspeccionar un flag, su entorno y sus reglas actuales para preparar una recomendación. Una escritura cambia un sistema externo. No agrupes ambos permisos solo porque una integración lo haga más cómodo.

## Separa intención, autorización, ejecución y estado observado

Un solo evento no basta para describir una acción sobre un feature flag. Un registro fiable contiene cuatro hechos diferentes, y mezclarlos oculta el fallo que después necesitarás diagnosticar.

La **intención** es lo que el agente pidió que ocurriera. Debe indicar un identificador estable del flag, el entorno, el valor solicitado o el cambio de reglas, el motivo y el alcance. Hay que capturarla antes de llamar al proveedor.

La **autorización** indica quién permitió esa intención. La aprobación humana debe vincularse al cambio propuesto exacto, no a una solicitud vaga como «permite que el agente gestione los flags». La persona que aprueba necesita contexto suficiente para decidir: entorno de destino, estado actual, estado propuesto, segmento afectado, vencimiento si existe y tarea o incidente que lo originó.

La **ejecución** registra la solicitud saliente y la respuesta del proveedor. Es una prueba de que la pasarela intentó realizar la acción aprobada. No demuestra que exista el estado deseado.

El **estado observado** procede de volver a leer el flag después de la escritura. Detecta cargas mal formadas, actualizaciones parciales, comportamientos predeterminados y llamadas enviadas al proyecto o entorno equivocado. La lectura posterior también tiene límites. Los clientes SDK en caché quizá no hayan recuperado la configuración modificada, y esa lectura no puede demostrar que el código detrás del flag funcione correctamente. Esas son observaciones independientes que pertenecen a la telemetría del despliegue y a la monitorización de la aplicación.

Esta distinción importa durante una reversión. Supón que un agente solicita `checkout_v2=false`, una persona lo aprueba y el proveedor devuelve éxito. Si un segundo operador cambia el flag antes de que el agente vuelva a leerlo, un registro ingenuo contará una historia limpia, pero falsa. Un registro correcto dirá que la solicitud aprobada tuvo éxito en el límite de la API y después informará del estado observado, incluida una versión o revisión si el proveedor la ofrece.

No permitas que un motivo escrito libremente sustituya estos campos. «Mitigar los errores del checkout» aporta contexto. No es un objetivo, un valor anterior, un valor nuevo aprobado ni un resultado final.

## Captura una envoltura de mutación antes de llamar al proveedor

El agente debe enviar una solicitud de cambio estructurada, no componer una solicitud HTTP arbitraria para el proveedor de flags. Una envoltura fija crea algo que un revisor puede leer y una pasarela puede validar.

Este ejemplo usa un flag booleano, pero la misma estructura sirve para configuraciones JSON, despliegues porcentuales y reglas de segmentación. Mantén separados los cambios de reglas y los cambios de valores escalares. Una regla de segmentación puede modificar mucho más la exposición de lo que sugiere un único valor true o false.

```json
{
  "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"
  }
}
```

El bloque `expected` evita una sobrescritura silenciosa. Dice lo siguiente: realiza esta mutación solo si el valor y la revisión actuales siguen coincidiendo con lo que inspeccionó quien la solicita. Si otra persona o automatización cambió el flag después de que el agente lo leyera, rechaza la solicitud y muestra el nuevo estado. Reintentar a ciegas es una mala respuesta. El agente debe volver a preguntar porque ya no cuenta con la base necesaria para actuar.

El `request_id` debe ser idempotente. Los fallos de red ocurren después de que un proveedor recibe una solicitud, pero antes de que el solicitante reciba la respuesta. Sin idempotencia, un reintento del agente puede crear eventos de auditoría duplicados o aplicar dos veces una regla porcentual cuando el proveedor modela las actualizaciones como parches. Guarda el ID de la solicitud y devuelve el resultado original si se repite el envío.

Una pasarela puede devolver un resultado con esta forma:

```json
{
  "request_id": "ffchg_01J8KQ4W6D7P",
  "status": "applied",
  "provider_request_id": "p_9d3ab",
  "authorization": {
    "approver": "ops@example.com",
    "approved_at": "2025-03-08T17:18:32Z"
  },
  "observed": {
    "value": false,
    "revision": "482",
    "read_at": "2025-03-08T17:18:35Z"
  }
}
```

No incluyas tokens del proveedor en ninguno de estos registros. Un registro de solicitudes que contiene credenciales acaba convirtiéndose en otro almacén de secretos, normalmente con peores controles de acceso y más copias.

## Una aprobación debe describir el alcance del impacto

Una persona no puede aprobar un cambio seguro basándose solo en el nombre de un flag. Los nombres cambian, los flags sobreviven a su intención original y un booleano puede ocultar una regla de segmentación extensa detrás de una etiqueta agradable.

La tarjeta de aprobación o la pantalla de revisión debe mostrar la representación actual junto a la representación solicitada. Para un despliegue porcentual, muestra los porcentajes anterior y nuevo exactos, la población o el segmento, cualquier flag previo necesario y el entorno. Para una edición de reglas, muestra la regla completa anterior y posterior en un formato canónico legible. Un diff que omite una cláusula porque parece repetitiva es la forma en que alguien convierte por accidente «empleados de la región A» en «todos los usuarios».

La persona que aprueba también necesita conocer el motivo y el vencimiento. Los cambios operativos temporales suelen volverse permanentes porque termina el incidente y todo el mundo sigue con otras tareas. Un vencimiento no revierte el cambio por arte de magia. Ofrece a un operador un momento programado para volver a evaluar el flag y crea un compromiso visible en el registro de la acción.

El alcance de la aprobación debe coincidir con la mutación, no con el agente. «Aprueba este proceso durante el resto de la sesión» puede tener sentido para inspecciones repetidas o para un conjunto predefinido de acciones que no sean de producción. Es un alcance deficiente para un despliegue en producción donde cada acción cambia una población de clientes distinta.

Yo usaría una aprobación independiente para cada mutación en producción cuando se cumpla cualquiera de estas condiciones:

- El cambio afecta a un control operativo, pagos, autenticación, autorización o retención de datos.
- La solicitud modifica una regla de segmentación, un segmento, un requisito previo o un porcentaje, en lugar de un único valor booleano.
- La acción apunta a producción o a un entorno conectado con tráfico real de clientes.
- El agente propone un valor que difiere de un plan de reversión aprobado.

Esto no es teatro de aprobación. La función de la persona no es volver a escribir la solicitud. Debe decidir si el alcance indicado y la situación operativa actual justifican la escritura. Si la tarjeta oculta el alcance, solo puede aprobarla mecánicamente.

Evita una aprobación permanente que diga que un agente puede «gestionar feature flags». Es popular porque elimina interrupciones. También convierte cada mutación posterior en una escritura de producción sin revisar, incluida la acción inusual que ocurre cuando el agente está confundido por un contexto obsoleto o por un resultado engañoso de una herramienta.

## La concurrencia vuelve insegura una reversión automática por defecto

Un agente solo puede revertir un flag cuando demuestra que está deshaciendo su propio cambio. El consejo habitual de «haz que el agente revierta siempre si hay un fallo» ignora a los operadores concurrentes y es inseguro.

Considera esta secuencia. A las 10:00, el valor actual es `true`, revisión 481. El agente recibe aprobación para establecerlo en `false` y el proveedor registra la revisión 482. A las 10:06, un ingeniero de guardia observa otro síntoma y establece deliberadamente el flag en `true`, revisión 483. A las 10:08, se activa la condición de monitorización del agente y este ejecuta la reversión prevista a `true`.

En ese caso concreto, el valor duplicado parece inofensivo, pero el mismo patrón con una regla de segmentación puede causar daños. El ingeniero de guardia quizá haya cambiado la regla para limitar una ruta a un único cliente. El agente restaura la regla amplia anterior porque conservaba una instantánea previa al cambio. Acaba de sobrescribir una intervención deliberada sin haberla visto.

Una solicitud de reversión debe incluir la revisión creada por la acción original como estado esperado. La pasarela debe aplicar la reversión solo si el proveedor sigue informando de esa revisión o de la configuración canónica exacta que escribió el agente. Si la condición falla, devuelve `needs_review` con la configuración actual. El agente puede explicar el conflicto a una persona, pero no debe resolverlo por su cuenta.

Usa una carga de reversión que incluya su acción principal:

```json
{
  "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
  }
}
```

Algunos proveedores no exponen revisiones ni APIs de actualización condicional. En ese caso, no puedes hacer que una reversión automática sea suficientemente segura para un flag de producción en disputa. Lee el estado, presenta la diferencia y exige aprobación humana para la escritura de restauración. Aceptar esa limitación es mejor que fingir que una marca de tiempo ofrece control de concurrencia.

Distingue también entre revertir un feature flag y recuperar el estado de los usuarios. Desactivar un flag puede detener la exposición futura, pero no revertirá migraciones de datos, trabajos en cola ni registros creados mientras la funcionalidad estaba activa. Cuando un flag controla escrituras, el contexto de aprobación debe indicarlo claramente.

## Restringe los verbos, los objetivos y las credenciales

Un agente debe tener permiso para solicitar un vocabulario limitado de acciones sobre flags, no acceso de administrador al proveedor. El token o la credencial de la API del proveedor deben mantenerse fuera del contexto del agente.

Empieza por enumerar los verbos permitidos. `get_flag` y `list_flag_metadata` son lecturas. `set_boolean_flag` es una escritura limitada. `set_rollout_percentage`, `replace_targeting_rule`, `create_flag`, `archive_flag` y `edit_segment` tienen consecuencias mucho mayores y deben ser operaciones independientes. No expongas una acción genérica como `PATCH /flags/{id}` suponiendo que las instrucciones harán que el agente sea cuidadoso. Los endpoints de parche genéricos permiten enviar campos que ningún revisor esperaba.

Después, restringe los objetivos. Vincula una credencial a un proyecto y un entorno cuando el proveedor permita ese alcance. En la pasarela de acciones, mantén una lista de flags y operaciones permitidos para el trabajo concreto. Un agente de lanzamiento que controla `checkout_v2` no necesita acceso a todos los flags de la organización.

Una solicitud de acción debe fallar antes de llegar al proveedor si intenta usar un verbo no aprobado, un entorno desconocido, una revisión esperada ausente o un objetivo no permitido. Esa validación debe ser determinista. Una política en lenguaje natural como «haz solo cambios seguros» da al agente una frase que interpretar, no un límite que aplicar.

Sallyport mantiene las credenciales HTTP en su bóveda cifrada y realiza la solicitud a la API sin pasar el secreto al agente. Esto resulta útil para este patrón porque el agente puede solicitar una acción mientras la credencial permanece en el Mac que lo controla.

Mantén separada la credencial del proveedor de la identidad propia del agente. El registro de auditoría del proveedor quizá solo vea una cuenta de servicio, pero tu registro de acciones puede identificar la sesión del agente, la tarea de origen y a la persona que aprobó la escritura exacta. Esa separación también facilita la revocación: puedes detener una ejecución concreta del agente sin rotar una credencial que usa un flujo legítimo de una persona.

No pongas un token de API en un archivo de configuración del agente «solo por este incidente». Los agentes copian el contexto en transcripciones, historiales del shell, parches generados y argumentos de herramientas con más facilidad de la que los equipos imaginan. Rotar el token después no elimina esas copias.

## Prueba la ruta de control con fallos, no solo con casos normales

Una integración de feature flags está lista solo después de comprobar cómo se comporta cuando fallan sus supuestos. El caso normal, leer el valor, aprobar y actualizarlo, demuestra muy poco.

Realiza una prueba controlada en un entorno que no sea de producción y fuerza deliberadamente estos resultados:

1. Cambia el flag después de que el agente lo lea y envía la solicitud original. La pasarela debe rechazar la revisión esperada obsoleta.
2. Envía dos veces el mismo ID de solicitud después de simular una respuesta perdida. La segunda llamada debe devolver el primer resultado registrado, no ejecutar una nueva mutación.
3. Rechaza la aprobación. El proveedor no debe recibir ninguna escritura y el registro de auditoría debe mostrar un rechazo, no un tiempo de espera ambiguo.
4. Permite que una persona edite el flag después de la acción del agente y luego intenta una reversión automática. La reversión debe detenerse para revisión.
5. Bloquea o revoca la sesión del agente durante una solicitud pendiente. La acción debe fallar antes de usar la credencial.

Estas pruebas revelan un problema de diseño sutil: muchos equipos solo registran los cambios correctos. Las solicitudes fallidas y rechazadas importan igual. Una solicitud rechazada indica que un agente intentó usar un alcance que no tenía. Un rechazo por escritura obsoleta indica que el sistema evitó una sobrescritura. Ambos registros explican por qué el estado del proveedor no cambió cuando un operador esperaba que lo hiciera.

Prueba también la canonicalización. Dos reglas de segmentación JSON pueden significar lo mismo aunque sus campos estén en un orden diferente. Si el código compare-and-set compara JSON sin procesar, producirá conflictos falsos. Si normaliza de forma demasiado agresiva, puede pasar por alto una diferencia semántica. Elige una representación canónica para el modelo del proveedor, regístrala y pruébala con campos reordenados, valores predeterminados omitidos y referencias equivalentes a segmentos.

Por último, prueba la ruta en la que el proveedor devuelve éxito, pero falla la lectura posterior. Registra `execution=accepted` y `observed=unknown`; no etiquetes como exitosa la solicitud completa. Alguien debe inspeccionar el estado del proveedor antes de que el agente realice un cambio dependiente.

## Un registro de auditoría debe sobrevivir a un incidente discutido

Un registro útil de feature flags debe responder a una pregunta escéptica: «¿Cómo sabemos que este relato del cambio no se editó después de los hechos?». Los registros normales de la aplicación suelen bastar para depurar, pero rara vez responden a esa pregunta cuando muchas personas pueden acceder al sistema de registros.

Escribe eventos de acciones en modo append-only con un número de secuencia, una marca de tiempo, la envoltura de la solicitud, el resultado de la autorización, el resultado de la ejecución y el estado observado. Vincula los eventos relacionados mediante IDs de solicitud y de solicitud principal. El encadenamiento de hashes hace visibles las modificaciones posteriores: cada evento incluye un resumen de su propio contenido y el resumen del evento anterior. La verificación comprueba la cadena en orden.

El encadenamiento de hashes no hace que un registro sea verdadero. No puede demostrar que la persona que aprobó una solicitud la entendiera ni recuperar registros que nunca se escribieron. Sí hace detectable la eliminación o modificación posterior cuando conservas la cadena y la verificas de forma independiente. Esa es la afirmación correcta y ya resulta más útil que llamar «inmutable» a un registro sin describir el mecanismo.

Conserva el historial nativo del proveedor de flags como evidencia de apoyo, no como el único registro. Relaciona los IDs de solicitud del proveedor cuando este los exponga. Vincula el `correlation_id` de la acción con un registro de incidente o un cambio de despliegue. Cuando alguien pregunte por qué se movió un flag, debes poder reconstruir la decisión sin hacerlo a partir de mensajes de chat y memoria humana.

Sallyport proyecta los registros de sesión y de llamadas individuales desde un registro de auditoría cifrado y encadenado mediante hashes, y `sp audit verify` comprueba la cadena sin conexión y sin una clave de bóveda. Así, un equipo puede verificar que su registro de acciones de control sigue siendo internamente coherente incluso cuando la bóveda permanece bloqueada.

Revisa las acciones rechazadas y los conflictos de escrituras obsoletas como parte del trabajo operativo normal. No son ruido. Un aumento de los conflictos puede indicar que varias automatizaciones controlan los mismos flags. Las solicitudes repetidas de objetivos rechazados pueden mostrar que el alcance de la tarea de un agente es demasiado amplio o está mal definido.

## Haz que el agente produzca primero una propuesta de cambio

El patrón operativo más seguro es sencillo: permite que el agente inspeccione, diagnostique y prepare la mutación, y después exige una ruta de escritura controlada para ejecutarla. La propuesta debe tener suficiente detalle para que otro ingeniero pueda aprobarla sin leer toda la transcripción del agente.

Para cada solicitud de producción, exige que el agente indique el estado actual que observó, el estado deseado exacto, la revisión esperada, por qué ayuda el cambio, qué podría verse afectado y cuál es la condición de reversión. Si no puede aportar esos datos, no ha demostrado que deba tener permiso de escritura.

No le pidas un ensayo largo. Pídele una solicitud completa. La diferencia importa. La prosa extensa suele ocultar que el agente nunca comprobó el entorno de destino o nunca recuperó la regla actual. Una envoltura estructurada muestra la omisión de inmediato.

Los equipos que adoptan esta disciplina descubren que muchos cambios propuestos no necesitan ejecutarse. El agente puede descubrir que el flag ya tiene el valor deseado, que el grupo con fallos no coincide con la regla o que la solución real es revertir un despliegue. Leer primero y registrar el estado esperado evita que el agente haga una escritura ceremonial solo para completar una tarea.

Un feature flag es un control rápido sobre el comportamiento activo. Da a un agente de IA la capacidad de usarlo únicamente cuando el sistema registra su solicitud, vincula una decisión humana con la mutación exacta, evita sobrescrituras obsoletas y verifica lo que almacenó el proveedor. Cualquier cosa por debajo de ese estándar deja tu interruptor de producción más cómodo conectado a una cuenta que nadie puede explicar por completo.
