kisenon
Agent-Safe Change Control

Guardrails

Presupuestos, niveles de política, autoridad acotada, análisis de riesgo y comprobaciones de radio de impacto — lo que detiene a un agente antes de que le haga daño.

Cinco salvaguardas rodean un sandbox de agente de IA. Dos son límites duros que el agente no puede exceder físicamente (LEASH, SCOPE), una convierte datos en un veredicto (POLICY), y dos producen datos para sopesar (LINT, BLAST). Ninguna pone un LLM en la ruta de confianza.

LEASH — presupuestos por sandbox

Bloquea: un agente que se descontrola — quemando sentencias, cómputo o tiempo de reloj sin límite.

Establezca un presupuesto cuando cree o ejecute el sandbox:

keon sandbox create \
  --budget-statements 500 \
  --budget-compute-seconds 120 \
  --budget-wall-seconds 900
# or the same three flags on: keon sandbox run …

En caso de incumplimiento el sandbox se autotermina: el estado pasa a discarded y budget_breached nombra qué límite reventó — statements, compute_seconds o wall_clock. La CLI sale con el código de error sandbox_budget_breached. Se dispara una advertencia al 80% de cualquier presupuesto.

En el cable, los presupuestos son un objeto budgets, una entrada por presupuesto:

"budgets": {
  "statements":      { "limit": 500, "used": 218, "warned": false },
  "compute_seconds": { "limit": 120, "used": 41,  "warned": false },
  "wall_clock":      { "used": 63 }
}

Un limit ausente significa ilimitado — no hay valor centinela que malinterpretar.

Configurar valores por defecto y topes (propietario/administrador):

# Per-project defaults double as the create-time cap.
curl -X PATCH .../v1/projects/{id} \
  -d '{"sandbox_budget_defaults": {"statements": 500, "compute_seconds": 120}}'

El valor por defecto es el tope: pedir en el momento de creación más que el valor por defecto del proyecto devuelve 422 sandbox_budget_exceeds_cap. Los valores por defecto por proyecto son configurables — no hay un número fijo que citar aquí.

Dos invariantes:

  • Congelado en la creación. Los presupuestos se fijan cuando se crea el sandbox; cambiar después los valores por defecto del proyecto nunca vuelve a atar un sandbox en vivo.
  • Las claves de agente solo aprietan. Una clave con capacidad de agente puede solicitar presupuestos más ajustados en la creación; nunca puede establecer los valores por defecto del proyecto.

POLICY — niveles de política de promoción

Bloquea: una promoción cuyos cambios son más arriesgados de lo que el proyecto permite — incluso una que un agente (o un humano) intente dejar pasar.

POLICY es una capa por proyecto que asigna una clase de riesgo a una acción, superpuesta sobre el promote_mode base.

Configurar (CLI):

keon projects promote-policy <projectId>                 # show effective policy
keon projects promote-policy <projectId> \
  --set destructive=block \
  --set unbounded=require_human \
  --on-conflicts require_human                           # merge-write
keon projects promote-policy <projectId> --clear         # drop the overlay

--set <class=action> es repetible y se fusiona en la capa existente.

Configurar (API): GET / PUT / DELETE /v1/projects/{projectId}/promote-policy:

{ "version": 1,
  "rules": { "destructive": "block", "unbounded": "require_human" },
  "on_conflicts": "require_human" }
CampoValores legales
clase de riesgoadditive, mutating, destructive, unbounded, rewrite
acciónauto_promote, require_human, block
on_conflictsignore, require_human, block

ignore es legal solo para on_conflicts, nunca como acción de clase.

La postura base proviene de promote_mode, y la capa la anula por clase:

promote_modeCada clase usa por defecto
selfauto_promote
humanrequire_human

Cada regla efectiva informa de dónde provino — source: overlay, promote_mode o default.

Lo que ve el agente cuando se bloquea: una promoción bloqueada devuelve 409 promote_blocked_by_policy con los detalles de la decisión adjuntos.

Regla clave: un Approve humano nunca puede anular un block de política. La política se reevalúa en el momento de la aprobación, de modo que block se mantiene frente al clic. La validación de política es con fallo cerrado / estricta — una política no analizable deniega, nunca se degrada a abierta.

SCOPE — autoridad acotada (carriles)

Bloquea: cualquier lectura o escritura fuera de los esquemas y tablas que declaró — el carril del agente.

Configurar (solo en el momento de creación):

keon sandbox create \
  --schemas app,analytics \
  --tables  app.users,app.orders
# omit both flags → unscoped (full-branch authority)

--tables sin --schemas se rechaza del lado del cliente como invalid_lane.

Dentro del fork el agente físicamente no puede escribir fuera del carril — una escritura fuera del carril falla dentro del fork con SQLSTATE 42501 (privilegio insuficiente) o 3F000 (nombre de esquema inválido). Las lecturas fuera del carril también se deniegan. Y la promoción rechaza cualquier cambio fuera del carril con 409 sandbox_out_of_lane.

En el cable el sandbox lleva un objeto scope (ausente = sin acotar):

"scope": { "v": 1, "schemas": ["app", "analytics"], "tables": ["app.users", "app.orders"] }

keon sandbox diff gana un objeto lane que lista cualesquiera violations[], cada una con un motivo — out_of_lane_schema, out_of_lane_relation o unresolvable_targets.

Dos límites:

  • Inmutable tras la creación. Ampliar un carril significa descartar + recrear — no hay ampliación in situ.
  • Solo objetivos directos. Un carril no gobierna los efectos secundarios transitivos alcanzados a través de triggers o funciones SECURITY DEFINER.

LINT — clasificación estática de riesgo

Produce: una clase de riesgo estática para cada sentencia del conjunto de reproducción — sin ejecución, sin LLM, sin recuentos de filas. Puramente textual.

No hay un comando nuevo. LINT aparece en tres lugares que ya lee:

  • dentro de keon sandbox diff como risk_report,
  • por acción en keon sandbox log,
  • como max_risk_class en el cable del sandbox.

Clases, de menor a mayor severidad:

additive  <  mutating  <  rewrite  <  unbounded  <  destructive

Un conjunto de reproducción vacío se clasifica como none.

Forma del informe:

{ "statements": [
    { "seq": 4, "risk_class": "unbounded",
      "reasons": ["where_trivially_true: DELETE guarded by WHERE 1=1 matches every row"] }
  ],
  "rollup": { "max_class": "unbounded", "counts": { "additive": 2, "unbounded": 1 } } }

Cada motivo es <snake_case_code>: <sentence>. Por ejemplo, WHERE true o WHERE 1=1 clasifica la sentencia como unbounded con el motivo where_trivially_true.

Dos cosas que recordar:

  • LINT es datos, no una decisión. Clasifica; POLICY aplica. LINT nunca bloquea nada por sí solo.
  • Falla hacia arriba. Ante la incertidumbre LINT asigna la peor clase plausible. Como la detección es textual, los recuentos de filas reales no son una entrada — un DELETE sin WHERE se lee como destructive tanto si la tabla contiene una fila como si contiene mil millones.

BLAST — simulación de radio de impacto

Produce: evidencia medida de lo que una promoción haría realmente — niveles de bloqueo reales, duraciones reales de retención de bloqueos, recuentos de filas reales y cualquier divergencia desde el fork.

keon sandbox dry-run <id>

Reproduce el conjunto exacto de sentencias del sandbox contra dos forks desechables del padre, mide el coste real, detecta la divergencia y luego destruye ambos. Nunca toca main, y el agente nunca recibe una credencial de fork. BLAST es consultivo — nunca bloquea una promoción; los conflictos se exponen como datos.

La referencia completa de campos, la semántica de conflictos y la lista de endpoints están en Sandboxes y promoción → Simulación de radio de impacto.

Cómo encajan entre sí

  • LINT y BLAST producen datos — uno estático, otro medido.
  • POLICY convierte esos datos en una decisión, con fallo cerrado, no anulable por un clic humano cuando dice block.
  • LEASH y SCOPE son límites duros que el agente no puede exceder en absoluto — aplicados en el fork, congelados en la creación.

Consulte Errores comunes para conocer las maneras en que estos cinco se malinterpretan habitualmente.