kisenon
Agent-Safe Change Control

Errores comunes

Antipatrones que anulan en silencio el escalado a cero y la seguridad de agentes — y cómo evitarlos.

Estos patrones no dan error. Pasan CI, parecen razonables en un diff, y anulan en silencio una garantía por la que usted paga — el ahorro del escalado a cero o la seguridad de agentes. Cada uno de los siguientes: qué ocurre, por qué duele y la solución.

El código keep-alive derrota al escalado a cero

Un agente añade «servicialmente» código que toca la base de datos con un temporizador. Cada consulta periódica cuenta como actividad y reinicia el temporizador de suspensión, de modo que un endpoint que diseñó para escalar a cero nunca duerme — y la inactividad deja de ser gratuita.

Llega de varias formas. Un heartbeat de frontend o backend:

// runs forever, holds the compute awake forever
setInterval(async () => {
  await pool.query("SELECT 1");   // "health check"
}, 30_000);

Un monitor externo de disponibilidad apuntado a un endpoint cuyo handler resulta que consulta la BD — de modo que cada sondeo despierta el cómputo:

app.get("/health", async (_req, res) => {
  await pool.query("SELECT 1");   // monitored every 60s → never idle
  res.send("ok");
});

O ajustes del pool de conexiones que mantienen una conexión viva con consultas de validación — un min por encima de cero, o un «calentador» serverless:

const pool = new Pool({
  min: 2,                         // keeps ≥2 connections open + validated
  // a validation/keep-alive query on each idle connection resets the timer
});

Solución: audite los diffs escritos por el agente en busca de accesos periódicos a la base de datos. Mantenga las comprobaciones de vida en la capa HTTP — sondee la aplicación, no la BD — y deje que el pool se vacíe hasta cero (min: 0). La vista de cómputo de la consola muestra por qué un endpoint no está escalando a cero, lo que expone rápidamente un heartbeat perdido.

Entregar al agente las credenciales de main cortocircuita ASCC

Dar a un agente la cadena de conexión de la rama main — o dejarle ejecutar keon con la sesión iniciada como su propio usuario — elude todo lo que ASCC aplica: aislamiento del sandbox, presupuestos LEASH, comprobaciones LINT y BLAST, compuertas de promoción, atribución y anclas de deshacer. El agente ahora escribe en producción directamente, y nada del bucle que hace seguros los cambios de agente llega a ejecutarse.

El agente nunca debería sostener una credencial que pueda escribir en main. La promoción es del lado del servidor por diseño — cp es el único escritor en producción.

Solución: acuñe una clave de API acotada a agente (capability = agent, scope = a project, expiración corta) en Settings → API keys, entregue al agente solo cadenas de conexión de sandbox y retire las credenciales más potentes de su entorno (sin DATABASE_URL completa, sin ~/.pgpass, sin sesión keon iniciada en el mismo shell). Consulte Entregar a un agente una credencial acotada y la sección SCOPE de Salvaguardas.

Tormentas de reintentos en torno al despertar

La primera conexión tras una suspensión tiene que despertar el cómputo, así que es más lenta que una en caliente. Un agente que ve una única conexión lenta puede «arreglarla» — con tiempos de espera de cliente agresivos y bucles de reintento que martillean el endpoint, o añadiendo un keep-alive (error #1) para no tener que despertar en absoluto. Ambos ceden el ahorro para tapar un coste de una sola vez.

Solución: establezca un connect_timeout de cliente de alrededor de 10 s y tenga paciencia en la primera conexión. El arranque en frío es de menos de un segundo dentro de la misma región una vez que las rutas calientes entran en juego — una conexión ligeramente lenta es esperable, no un defecto que haya que sortear con ingeniería.

postgresql://…?connect_timeout=10

Credenciales confirmadas en el código

Los agentes codifican de forma fija cadenas de conexión y claves de API en el código fuente y en archivos .env que luego llegan a git. Las claves filtradas se recolectan a las pocas horas de llegar a un repositorio público (o que luego se hará público) — la ventana se mide en horas, no en días.

Solución: inyecte los secretos mediante el entorno, nunca los confirme. Mantenga los archivos .env fuera de git. Ante cualquier filtración, rote de inmediato desde Settings → API keys — revoque la clave expuesta y acuñe una nueva.

El DDL directo sobre main elude el bucle de promoción

Ejecutar una migración directamente contra main se salta la captura que hace un cambio reversible y auditable. Pierde la migración up/down emitida (EMIT), la entrada firmada del ledger (LEDGER) y el ancla de deshacer (UNDO). El esquema cambió, pero no hay registro que la plataforma pueda reproducir o revertir.

Solución: sandbox → promoción, incluso para un cambio de esquema «trivial». El bucle de promoción es lo que produce la migración, la entrada del ledger y el ancla; un ALTER directo no produce ninguno de ellos.

Las escrituras dentro de una transacción revertida igualmente aterrizan

La captura registra las sentencias que el agente ejecuta — no tiene conciencia de los límites de transacción. Las sentencias ejecutadas dentro de un BEGIN … ROLLBACK se capturan igualmente, y si ese sandbox se promociona, se reproducen y se aplican. Un ROLLBACK en el sandbox no las descaptura.

BEGIN;
UPDATE users SET plan = 'pro';   -- captured
ROLLBACK;                        -- does NOT remove it from the capture

Solución: no confíe en ROLLBACK dentro de un sandbox para «deshacer» trabajo exploratorio. Si quiere que el trabajo desaparezca, descarte el sandbox — esa es la vía de eliminación que la captura respeta.

Aparcar trabajo en un sandbox más allá de su presupuesto o TTL

Los sandboxes son efímeros. Cuando un sandbox agota su presupuesto LEASH se descarta automáticamente (status=discarded), y cualquier trabajo sin promover en él se pierde. Tratar un sandbox como una rama de larga vida a la que «volverá» es como se esfuman los cambios de un día.

Solución: promociónelo, o vuelva a capturar el trabajo en un sandbox nuevo. Trate los sandboxes como desechables por defecto — el artefacto duradero es la promoción, no el sandbox.

Malinterpretar las garantías

Tres trampas específicas en lo que las comprobaciones realmente prometen:

  • La simulación de radio de impacto es consultiva. Mide lo que una promoción haría — bloqueos, duraciones, recuentos de filas reales — pero nunca controla la promoción. Una simulación limpia es información, no una luz verde; y si una simulación es obligatoria antes de promocionar es decisión de POLICY, no de la simulación.

  • Approve no puede anular un bloqueo de política. Un Approve humano nunca puede dejar pasar un block de política ni una sentencia fuera del carril. La única manera de superar un bloqueo es un cambio de política auditado — no hay interruptor de anulación manual, por diseño.

  • Un fork enmascarado enmascara valores, no forma. En un fork enmascarado los valores están enmascarados, de modo que el DML dependiente de datos que el agente escribe contra esos valores enmascarados no coincidirá con las filas reales del padre durante la reproducción. El trabajo de carril de esquema es independiente del valor y se reproduce fielmente; el DML dependiente del valor desarrollado contra datos enmascarados no.