El verde que no probaba nada

Un test que pasa dice que algo se cumplió. No dice que se haya ejecutado.
Estuve construyendo ControlShift, un preflight de migraciones industriales: lee el programa de un PLC Allen-Bradley viejo y decide si un integrador puede cotizar esa migración a precio fijo. Todo su valor está en negarse a adivinar — la evidencia ausente jamás se convierte en «compatible». Con esa promesa, un falso verde no es una molestia: es exactamente el fallo que el producto existe para impedir.
Encontré cuatro. Ninguno lo detectó una suite en rojo.
1. El fixture que entraba por la puerta de atrás
El seeder escribía las filas de artefactos directo a Postgres. Rápido, cómodo, y saltándose siete controles de ingesta a la vez: la lista de extensiones permitidas, el rechazo de ejecutables, el tope de tamaño, la escritura irrepetible del objeto, la auditoría — y forzaba el estado SCANNED sobre archivos que ningún antivirus había visto nunca.
Cuarenta y ocho aserciones de API pasaban encima de eso. Todas verdes, todas sobre un estado que ningún usuario podría producir por la interfaz.
Lo arreglé haciendo que el seeder llame al mismo servicio que llama la capa HTTP. Un contexto de aplicación, dos líneas, y hereda todos los controles sin poder desincronizarse de ellos. La primera siembra con el escáner real generó once eventos de auditoría que antes sencillamente no existían.
La regla que me llevo: un fixture que entra por la puerta de atrás no prueba el producto, prueba la base de datos.
2. La extensión decidía el veredicto
Este apareció al correr el flujo completo por la API en vez del seeder. El veredicto comercial cambió, y tardé un rato en aceptar que el test tenía razón.
Un NETWORK_SKETCH.pdf se clasificaba como plano eléctrico, porque .pdf estaba mapeado a un tipo concreto. La cobertura de red cayó de 33 % a 0, la ponderada de 54 % a 47, y el veredicto presupuestario pasó de LISTO CON RESERVAS a NO LISTO.
Nadie escribió nada mal. El archivo era un PDF.
Un PDF puede ser un plano eléctrico, un croquis de red o un informe, y cuál de los tres sea mueve un dominio de evidencia que decide si se puede cotizar. Hoy un .pdf entra sin clasificar y no aporta evidencia hasta que una persona dice qué es. Una extensión no tiene autoridad para mover un veredicto.
3. El encabezado desconocido borraba el programa
Le di al parser un archivo con encabezado ajeno pero con lógica válida adentro. Devolvió cero rungs, un modelo vacío y ningún hallazgo de software — incluidas las dos instrucciones que bloquean la migración entera.
No crasheó. No hubo excepción. Una evaluación limpia sobre un programa que nunca se leyó, que en este dominio se lee como «no encontramos nada mal».
Dos arreglos. Los rungs ahora sobreviven a un encabezado ilegible: la sintaxis de rung es la parte del formato que sí está confirmada públicamente, así que un contenedor desconocido nos cuesta el contenedor, nunca la lógica. Y una regla dispara BLOQUEADO cuando un source entregado no produce ningún rung. Un archivo que no entendimos no puede parecerse a un archivo sin problemas.
4. El script que cazaba falsos verdes produjo uno
Este es el mejor. Escribí un verificador que corre las cinco capas del proyecto y da un veredicto único. Su primera corrida imprimió:
[ok] 0 tests
bc no existía en ese shell, la suma de tests falló en silencio, quedó en cero — y el script lo reportó como verde. Escribiendo la herramienta cuyo único propósito era cazar falsos verdes, produje uno.
Ahora tiene un guardián explícito: si el motor reporta menos de treinta tests o la API menos de cuarenta aserciones, falla. Una corrida que no ejecutó nada no puede parecerse a una que pasó.
Lo que comparten los cuatro
En ninguno hubo una excepción, un stack trace ni un test rojo. En los cuatro, la comprobación pasó porque lo comprobado nunca ocurrió: el escaneo que no corrió, el tipo que nadie declaró, el parseo que devolvió vacío, la suma que dio cero.
La defensa no es más tests. Es preguntarle a cada verde una cosa incómoda: si esto no se hubiera ejecutado, ¿se vería distinto? Si la respuesta es no, ese verde no está midiendo nada.
Por eso la suite ahora rompe invariantes a propósito para comprobar que muerde — apagué la compuerta de escaneo, el aislamiento por tenant, la validación de logos y la regla de que proponer no aprueba: las cuatro produjeron fallos. Y por eso el fixture entra por la puerta principal, la extensión no decide nada que mueva dinero, y un verde con cero tests es rojo.
Comentarios
Todavía no hay comentarios. Empieza tú.