Zones

Nombra los paths que harían daño. Todo lo demás queda abierto.

La mayor parte de un repositorio es segura para que un agente la cambie. Unas pocas partes no lo son — el schema, los contracts, lo que diga tu historial de incidentes. Una zone es cómo dices cuál es cuál, en un fichero que revisas como código, y es lo único que CommitCycle de verdad impone.

Cuatro cosas, y una de ellas es una persona

Los path patterns dicen dónde. Un risk level dice cuánto cuidado. Una default policy dice qué pasa cuando no se ha concedido nada. Y un owner dice a quién preguntar — que es el atributo que convierte un muro en una vía de entrada.

  • Path patterns — las mismas formas glob que usan los rulesets de GitHub, nada nuevo que aprender
  • Risk level — high, medium, low. High significa que se pregunta al owner antes de empezar el trabajo
  • Default policy — deny, read-only u open, aplicada cuando ningún grant nombra la zone
  • Owner — una persona real, en un fichero, no en la memoria de nadie
.zones/zones.yml · committed
# El mapa propio de CommitCycle, recortado. Cuatro zones en el fichero real, no treinta.
zones:
  - id: schema
    risk: high
    owner: paulo@commitcycle.com
    paths:
      - "apps/api/migrations/**"
      - "apps/api/src/db/schema/**"
    default_policy: deny

  - id: enforcement
    risk: high
    owner: paulo@commitcycle.com
    paths:
      - "packages/hook/**"
      - "packages/action/**"
    default_policy: deny

  - id: brand
    risk: medium
    default_policy: read-only

# Todo lo que no está aquí queda sin proteger, a propósito.

El acceso llega como un grant, y se va solo

Mover una task a In Progress es lo que lo emite. No hay comando que abra una zone, así que no hay una vía secundaria que encontrar — y nadie tiene que acordarse de cerrar nada.

Atado a una task

Abre las zones que esa task declaró, y nada adyacente. El cambio vecino tentador es justo el que los non-goals existen para nombrar.

Atado a una rama

Dos agentes en un mismo repositorio responden cada uno a su propio grant. Éste es el fallo que este mismo producto sufrió primero, y el arreglo está registrado como D-43.

Caduca en ocho horas

Cien micro-consentimientos cambiados por un macro-consentimiento con un reloj puesto. Pedir permiso en cada llamada es seguridad por fatiga.

Blocked14:02 · task CC-42

Write apps/api/migrations/0007_add_org_index.sql

Zone
schema · risk high
Task declared
api, web
Owner
paulo@commitcycle.com

Al agente se le dice por qué en la misma respuesta que se lo deniega, así que pide acceso en lugar de intentar otra vía. Un bloqueo que sólo dice que no acaba siendo esquivado.

Access requestwaiting · 2 min

CC-42 quiere schema

Reason
La migración necesita el índice del org
Scope
write · apps/api/migrations/**
Expires
4 horas tras la aprobación
Approve for 4hDeny

Just-in-time: el grant caduca solo. Nadie tiene que acordarse de cerrarlo, que es justo el paso en el que falla cualquier proceso de acceso.

Bloquear es commodity. El modelo de debajo no lo es.

Mejor decirlo antes de que lo descubras tú: denegar una tool call en el momento ya lo tienen Claude Code, Codex, Cursor, Augment, Factory y Devin CLI, y es gratis en el que ya estés usando. Si eso fuera el producto, no necesitarías esta página.

Lo que ninguno de ellos tiene es el modelo que consulta esa denegación. Sus reglas son por máquina y permanentes. No hay un owner a quien preguntar, ni un momento de aprobación, ni caducidad, ni noción de una task a la que el permiso pueda estar atado.

Las reglas de todos los demás

Una lista de paths. Fijada una vez, cierta para siempre, igual para cualquier trabajo, sin nadie asociado.

Una zone más un grant

Path × owner × risk × esta task × esta rama × ocho horas, y un registro de quién lo abrió y por qué.

Contra CODEOWNERS y los rulesets de rama la diferencia es el cuándo: mismo vocabulario, preguntado después de que el cambio ya existe, impuesto en el host. Una zone se comprueba en la escritura, en tu portátil, sin conexión — y CI sigue recalculando todo el diff después.

Qué se midió, y qué no demuestra

Cada cifra aquí lleva su límite en la misma frase. Es una regla de la casa, no modestia.

  • 25/25 vectores de escape de Bash contenidos — las escrituras de shell corren contra un snapshot de git y todo lo que quede fuera de tus zones se revierte byte a byte.El corpus lo eligió el propio autor. El eval de falsos positivos en vivo aún no ha corrido.
  • 0/20 falsos positivos sobre ese mismo guard.Mismo corpus autoelegido. Veinte comandos no son veinte tasks reales.
  • 8/20 falsos positivos en el allowlist conservador — el enfoque querechazamos, y la razón por la que ganó la contención.Una herramienta que bloquea trabajo legítimo se desinstala en la segunda semana. Eso se midió, no se adivinó.
  • 68–83 ms en p95 para la decisión, contra un presupuesto de 100 ms.El p99 tocó 102 ms en un caso. El margen es estrecho y las palancas están nombradas.

Dónde se detienen las zones

  • Confinan a cada agente; no arbitran entre ellos. Dos agentes que discrepan siguen discrepando — cada uno simplemente queda sujeto a su propia task y su propia rama.
  • Sin proteger es lo normal, y debe serlo. Un gate demasiado celoso cuesta más que uno que falta, así que todo lo que no declares queda simplemente abierto.
  • Los topics nunca imponen. Las zones imponen paths; las disciplinas que una task declara sólo aconsejan. Las dos cosas nunca se mezclan.
  • El registro sobrevive. El mapa, los grants y el audit trail son ficheros en tu repositorio. Desinstala CommitCycle y te quedas con todo.