Los controles son el producto
Un agente intentó publicar un commit que no existía. Todo parecía correcto. Esta es la historia de los controles que dijeron que no.
Por Erick Agrazal, Fundador
Una vez, un agente intentó publicar un commit que no existía.
Nuestro monorepo registra sus servicios como submódulos. El repositorio principal guarda un apuntador hacia un commit específico de cada repositorio hijo. Hay un comando de bajo nivel que escribe uno de esos apuntadores. Recibe un hash y no comprueba que pertenezca a un commit real. Puedes darle cuarenta caracteres hexadecimales inventados y terminará en silencio. git status se verá limpio.
Un agente intentó reconstruir un apuntador y produjo un hash que nunca había existido. Todas las comprobaciones locales pasaron. El pull request estaba en verde. El fallo apareció al final, en la máquina de despliegue, varios minutos y un intento de producción después.
La solución no fue buscar un agente mejor. Añadimos una comprobación antes de cada despliegue que hace una pregunta aburrida: ¿cada apuntador existe de verdad en su repositorio remoto? Si no obtiene un sí definitivo, se detiene. Son poco más de veinte líneas de script y han parado más despliegues malos que cualquier revisión que yo haya leído.
La diferencia entre parecer y ser
Los agentes son muy buenos produciendo cosas que parecen correctas. Casi podríamos definirlos así. Su resultado es la plausibilidad.
La mayor parte del tiempo, lo plausible y lo correcto coinciden. Cuando se separan, nada dentro del resultado te dice cuál tienes delante. Revisar con más intensidad no siempre cierra esa distancia porque una revisión también juzga si algo parece razonable. El hash inventado tenía la longitud correcta, usaba los caracteres correctos y estaba en el campo correcto.
La salida es consultar la realidad en lugar del resultado. Todo control útil tiene esa forma. Solo puede satisfacerse con algo que vive fuera de lo que estamos comprobando. No preguntes si una cadena parece un commit. Pregúntale al repositorio remoto si ese commit existe.
Los controles, más o menos en orden
Nada entra sin un pull request. Las ramas de integración y producción están protegidas. Ningún agente tiene un camino alterno. Es el control menos inteligente y el que más trabajo hace. Cada cambio deja un diff, una ejecución de pruebas y un lugar donde un revisor puede objetar. No hacemos una excepción por urgencia. La urgencia es precisamente cuando alguien intentaría usarla.
Los revisores no tienen que estar de acuerdo. La primera nota describió el grupo de revisión. Lo importante es lo estrecho de cada encargo. Quien vigila los límites entre equipos no decide si el código es bueno. Solo pregunta si una consulta podría alcanzar datos de otra familia. Le decimos que encontrar un motivo para rechazar es un buen resultado.
Los revisores con una pregunta concreta rechazan cosas. Los que reciben un simple “revisa el pull request” suelen aprobar porque aprobar es la forma más fácil de estar de acuerdo.
La promoción exige procedencia. Antes de mover algo a producción, un script recorre los cambios de integración y pregunta a qué tarea validada pertenece cada uno. Cualquier cambio que no pueda explicar detiene la entrega.
Al principio ese control era demasiado estricto. Algunas ramas usan merges completos y otras compactan cambios, así que el mismo trabajo puede aparecer con hashes distintos y parecer un desconocido. Ahora comparamos el contenido del parche, no la identidad del commit. Publicamos primero la versión estricta y nos costó varios bloqueos falsos. Acepto ese intercambio.
La configuración no se observa de lejos. Se fija. La revisión previa compara los valores importantes con lo esperado y rechaza cualquier diferencia. Los incidentes por configuración son los que recuerdo años después. Nada está caído, todos los chequeos responden y el comportamiento es discretamente incorrecto.
Cerrar ante la duda tiene un costo
La comprobación de apuntadores se cierra ante la duda. Si no puede verificar, se niega a continuar. Es la decisión correcta y no sale gratis.
Una tarde, la API remota respondió con lentitud. El control no pudo confirmar apuntadores que eran perfectamente válidos y mantuvo la entrega bloqueada durante buena parte de una hora. Nada estaba roto. El control hizo exactamente lo que le pedimos y aun así perdimos la tarde.
Ese es el trato, no un defecto que vayamos a eliminar. Un control que se rinde cuando tiene dudas estará ausente justo el día en que la infraestructura tenga problemas. Ese es el día para el que existe. Cerrar ante la duda produce falsas alarmas. Abrir ante la duda produce incidentes que te cuentan los usuarios.
Existe una excepción de emergencia documentada. Se usa poco y deja un rastro. Saltar un control debe ser una decisión visible con una persona responsable, no algo que alguien logra comentando una línea bajo presión.
La etapa sin inteligencia
Quitamos los agentes de la última etapa a propósito.
Todo lo que llega allí ya fue revisado y validado. No queda ningún juicio por ejercer. Solo queda una secuencia: comprobar la procedencia, promover, publicar, probar y alinear las ramas. Un responsable, nada de concurrencia y ninguna pieza capaz de tener una idea.
Añadir agentes creativos no compraría calidad. Sí añadiría nuevas formas de competir entre sí: dos promociones mezcladas, apuntadores que cambian debajo de otra ejecución o una reversión que cae encima de un despliegue.
La construcción es donde varios agentes ayudan. La etapa de control es donde varios agentes se convierten en la amenaza.
Se siente como papeleo
El fallo más honesto de todo esto es humano, no técnico.
Cuando un control detiene una entrega, la primera sensación es que está siendo quisquilloso. Parece confundido, el trabajo se ve bien y uno quiere completar el papeleo y seguir. Yo también he sentido eso y me he equivocado más de una vez. En nuestro caso, un bloqueo que parecía contabilidad detectó correctamente trabajo sin validar en la rama.
Por eso seguimos esta regla: cuando un control dice que no, nuestra primera hipótesis es que tiene razón. Los controles no son infalibles. La tarde perdida lo demuestra. Pero casi logramos convencernos de ignorar un aviso correcto porque no sonaba dramático.
En la primera nota del blog escribí que el sistema de permisos es el producto, no una capa encima. Aquí ocurre lo mismo un nivel más abajo. Lo que hemos construido alrededor de los agentes es un conjunto de cosas capaces de decirles que no.