Ir al contenido

Blog ·

Una ejecución que imprimió su propio fallo

La ejecución de verificación escribía cada código de salida en un resumen y luego escribía DONE igualmente. Salió una versión sobre una línea roja sin leer.

Por Provibr

Antes de una versión ejecutamos un solo script. Lanza la suite de pruebas de la web, las suites de los paquetes, de la pasarela y de las herramientas, diez comprobaciones de tipos, el lint, la comprobación de contenido, el lint del protocolo y la generación de código del protocolo, y escribe una línea por paso en un fichero de resumen: el nombre del paso y su código de salida. Después escribe DONE.

Escribía DONE incluso cuando algunos de esos códigos de salida no eran cero.

El siete de septiembre salió una versión mientras el resumen contenía una línea que decía bun test packages/gateway/tools exit 1. Yo había leído los contadores de aprobados y fallidos de dos suites y no los de la tercera. No se rompió nada: la prueba que fallaba era una guarda sobre las cabeceras de los scripts de medición, así que el producto no se vio afectado y el cliente no vio nunca nada. El desenlace fue bueno y la forma era mala, y la forma es la única parte que merece la pena escribir.

Los contadores no son la puerta

La razón por la que esto es bochornoso y no simplemente mala suerte es que el modo de fallo tiene nombre en nuestras propias notas, y ese nombre es verde vacuo: una comprobación que no está conectada a una decisión no se lee, y una comprobación que se lee con los ojos se lee como lee una persona, es decir, buscando lo que espera ver.

El resumen estaba diseñado para hojearse. Cada suite imprime sus propios totales en algún punto más arriba, así que el movimiento natural es mirar «4515 pass, 0 fail» y darlo por terminado. Los códigos de salida estaban una pantalla más abajo, en un fichero cuya última línea decía DONE.

La reparación son cuatro palabras de shell. Después de todos los pasos, el script busca en su propio resumen cualquier código de salida entre uno y nueve y, si encuentra alguno, añade una línea que empieza por FAIL:. La regla que la acompaña es que un DONE sin un FAIL es la puerta, y que los contadores no lo son. La segunda mitad de esa regla importa más que la primera: quien tiene una señal barata y correcta deja de construir costumbres caras alrededor de una poco fiable.

Hay una regla compañera, y es que una orden de despliegue nunca comparte cadena de shell con una verificación que solo imprime. Si la verificación no puede hacer fallar la cadena, es documentación.

Qué estaba rojo de verdad

La guarda que falló es una de una familia, y merece la pena describirla porque es inusualmente barata para lo que compra.

El directorio de la pasarela guarda los scripts de medición: barridos de navegador, sondas de disposición, herramientas de siembra y limpieza, las cosas que una ronda escribe para demostrar algo y luego deja atrás. Hoy hay poco más de quinientos. Son scripts sencillos sin comprobación de tipos, lo que significa que lo único que se interpone entre ellos y la podredumbre es que a alguien le dé por ejecutar uno.

Cuatro cribas pasan por encima de todos ellos en una suite de pruebas normal:

  1. Todos los scripts se analizan, usando el motor de ejecución que de verdad los ejecuta.
  2. Toda importación relativa se resuelve a un fichero que existe. Esa es la clase de muerte que un analizador no ve: el script es sintácticamente perfecto y se cae en la primera línea al ejecutarlo.
  3. Todo script lleva una cabecera con prosa dentro. Sin una explicación, una herramienta de hace cuatro rondas es indistinguible de una que todavía importa.
  4. Toda cabecera nombra la ronda de la que viene, en una de exactamente dos formas fijas.

La cuarta estaba roja. Tres scripts de la ronda de documentación tenían cabecera, buena, y ninguna marca de ronda. Ese es el incidente entero: una convención de nombres, detectada por una guarda que existe para que quinientos scripts sigan siendo legibles, sentada en una línea de resumen que nadie leyó.

Por qué desconocido tiene que costar un hash de commit

La cuarta criba acepta dos formas y nada más. O la cabecera dice el nombre de la ronda con una fecha y de dónde salió esa atribución, o dice que la ronda es desconocida y lleva el hash del primer commit del fichero, con una fecha.

Al nombre no se le permite explícitamente ser la palabra «desconocida». Sin esa exclusión, «ronda desconocida, 2026-09-04» es un nombre con fecha perfectamente válido, y la rama cara se puede esquivar con una palabra. Tal como está, admitir que no se sabe cuesta un hash que alguien tiene que ir a buscar, y para cuando lo ha buscado suele saber ya la ronda.

La fecha es obligatoria por otra razón. Un nombre a secas es prosa, no una marca: una frase como «la ronda que también tocó el trabajo de cabeceras» contiene un nombre de ronda y no afirma nada sobre el fichero en el que está. Con una fecha adjunta pasa a ser una afirmación sobre este script, hecha un día concreto, que es la cosa más pequeña por la que se puede pedir cuentas a alguien.

Una puerta tiene que poder estar en cero

La pregunta evidente sobre quinientos scripts sin tipos es por qué no les pasamos la comprobación de tipos. Lo medimos, y la respuesta es instructiva.

La configuración existe. Es un instrumento y no una puerta, y no se ejecuta en el script de verificación. Medido sobre los scripts tal como estaban:

ConfiguraciónErrores
Con los ajustes estrictos de este espacio de trabajo3180
Sin modo estricto398
Sin modo estricto, tras hacer tipable un fichero compartido159

Una puerta tiene que estar en cero, y esos 159 restantes en su mayoría no son defectos. Se recorrieron dos familias y las dos resultaron ser artefactos de tipar código sin tipos: un parámetro sin valor por omisión que se cae de la forma inferida, y un bucle de desestructuración sobre un array mixto que se ensancha a una unión. Veintisiete de ellos son un único y mismo diagnóstico, sobre importar un fichero TypeScript desde un script que corre bajo un cargador que lo maneja perfectamente.

Lo que sí compró el instrumento es el paso de 398 a 159. Una línea de un ayudante de navegador compartido, un constructor que asigna sus argumentos sobre la instancia en bloque, mantenía vivos 239 errores, porque todo acceso a una propiedad de ese objeto en todos los scripts era irresoluble. Una reparación, 239 errores fuera. Eso es un buen retorno para una medición a la que se le permite ser distinta de cero, y es justo la clase de retorno que no se obtiene de una puerta, porque una puerta que no se puede satisfacer se acaba apagando.

La comprobación que medía su propio motor de ejecución

Hacer que funcionara la comprobación de análisis costó dos intentos, y los dos fallaron de maneras que parecían problemas de producto.

La primera versión pedía al motor de ejecución actual que comprobara cada fichero. Bajo nuestro ejecutor de pruebas, el motor actual no es el motor bajo el que corren los scripts, y su bandera de comprobación significa algo completamente distinto. El resultado fueron 301 informes de ficheros rotos sintácticamente, con líneas de fuente citadas como texto de error. Todos ellos estaban bien.

La segunda versión nombraba el motor correcto de forma explícita y aun así falló, de otra manera: el ejecutor de pruebas recoge los procesos hijos que pertenecen a una prueba, y desde aproximadamente la mitad de la lista cada llamada volvía con un estado nulo. Muerto por una señal, no por un error de análisis. Una guarda que se pone roja al azar no es una guarda.

La versión que funciona lanza un proceso hijo que comprueba él mismo los ficheros, de ocho en ocho, en unas nueve décimas de segundo cuando se midió. Lo que se afirma no ha cambiado: si el motor que ejecuta estos scripts los aceptará.

El paralelismo tampoco es un capricho. En serie, la comprobación superaba el límite de tiempo por prueba, y una guarda que agota el tiempo se lee como una guarda rota y no como una lenta.

La cota inferior que nadie pide

Hay una quinta prueba en ese fichero que afirma únicamente que hay más de cincuenta scripts que comprobar.

Un recorredor de directorios que no encuentra nada vuelve trivialmente cierta toda afirmación posterior. Renombre el directorio, cambie el filtro de extensión, rompa el recorredor, y cuatro cribas verdes informan sobre una lista vacía. La cota inferior está deliberadamente muy por debajo del número real, porque la idea no es impedir la limpieza; es hacer visible la diferencia entre «no hay nada mal» y «no se examinó nada».

El mismo fichero de pruebas es honesto sobre sus límites, y esa honestidad forma parte del diseño. Ninguna de las cuatro cribas demuestra que un script siga midiendo lo que dice. Un selector que ya no existe, una ruta que se movió, una columna que se eliminó: las cuatro comprobaciones pasan. Es un suelo, no una comprobación de tipos, y decirlo en el fichero impide que la persona siguiente trate una ejecución verde como más de lo que es.

Lo que dejaríamos por escrito

  1. Una verificación que solo imprime no es una puerta. Tiene que poder hacer fallar lo que viene después.
  2. Escriba la línea de fallo, no solo los códigos de salida. La puerta es una palabra que alguien puede buscar, en un sitio fijo, no un número que tiene que notar.
  3. Nunca encadene un despliegue detrás de una comprobación que no puede detenerlo. La cadena es la promesa.
  4. Los contadores son un resumen, no un veredicto. La gente lee el número que espera ver.
  5. Una puerta tiene que poder estar en cero. Si una medición no puede, consérvela como instrumento y dígalo, o acabará desactivada y luego ignorada.
  6. Encarezca la escapatoria barata de una regla. Si admitir ignorancia cuesta una palabra, todo el mundo escribe la palabra.
  7. Una comprobación que falla al azar no es una comprobación. Persiga la intermitencia antes de fiarse de la señal.
  8. Afirme una cota inferior sobre lo que encontró el recorredor. Cuatro comprobaciones verdes sobre una lista vacía se ven exactamente igual que cuatro comprobaciones verdes.

Para que quede claro qué es esto: la línea de fallo está en el script que está en el repositorio, y desde entonces ha corrido sobre fusiones que salieron verdes. Todavía no se ha demostrado con una ejecución roja en uso real, solo con el resumen frente al que se escribió. Las cifras de tipado son de una medición de un día y el recuento de ficheros se mueve cada noche.

Del trabajo de plataforma en Provibr. Otra guarda que tuvo que demostrar su propio cero está en una excepción de accesibilidad que se mide sola, y un campo que guardaba en silencio una intención en lugar de un hecho está en una fecha futura no es un calendario.

Empiece con un host y un agente

Cree una cuenta, instale el agente con un solo comando y conecte su primer host de Proxmox. El periodo de prueba dura 14 días y no pide ningún dato de pago.