El escaneo que se ofreció a importarse a sí mismo
Greenhouse tiene una regla a la que vuelvo una y otra vez: nada se borra, y nada se mueve sin preguntar. Así que al construir la pieza que permite apuntar la app a una carpeta donde ya hay proyectos - en vez de una carpeta vacía y nueva - el motor se diseñó de la misma manera. Escanea la carpeta, muestra lo que encontró, y solo toca el disco una vez que se confirma.
Esa mitad del motor en realidad se construyó semanas atrás, en otra sesión, y quedó marcada como terminada. Esta semana finalmente la conecté a una pantalla real. Y a los cinco minutos de probarla de verdad, se encontró a sí misma.
El escaneo que se escaneó a sí mismo
Apunté el escaneo de importación a un vault recién inicializado - la estructura de carpetas que Greenhouse crea automáticamente, antes de agregar un solo proyecto. El escaneo devolvió nueve resultados. Nueve carpetas que quería que yo asignara a una etapa del flujo. Había exactamente un proyecto en ese vault: ninguno. Cada resultado era la propia estructura interna de Greenhouse - la carpeta de ideas, la carpeta del vault, cada carpeta de etapa que acababa de crear para sí misma.
La función de escaneo en sí estaba bien. Hace exactamente un trabajo: listar subcarpetas, saltar cualquier cosa oculta. .greenhouse empieza con un punto, así que esa se saltó correctamente. Pero ninguna de las carpetas de trabajo propias de la app empieza con un punto. No están ocultas, son solo internas. El escáner no tenía forma de saber que “interno” y “oculto” no son lo mismo, porque nadie le había pedido nunca que supiera la diferencia - la única prueba que había recibido era una carpeta llena de subcarpetas de proyecto genéricas y comunes. Un escaneo de un vault ya inicializado era un escenario que simplemente nunca se había dado antes, porque nada había llamado nunca a este código con un vault real como entrada.
La solución es casi aburrida: la función genérica de escaneo se queda genérica, sin opiniones sobre qué es un “vault”. Una capa más arriba, donde ya está cargada la configuración real, construí la lista de exclusión - la carpeta de ideas, la carpeta del vault, cada etapa configurada - y filtré ahí en su lugar. Que la herramienta tonta siga siendo tonta, que la capa inteligente sea la inteligente.
La segunda versión del mismo error
Una vez arreglado eso, empecé a probar qué pasa después de importar algo de verdad. Asignar una carpeta a una etapa, hacer clic en el botón, ver que aparece en la lista de proyectos. Luego, por costumbre, volví a correr el escaneo.
La carpeta que acababa de importar seguía en los resultados. Ofreciéndose a sí misma para ser importada otra vez.
Esta tenía una explicación más clara una vez que lo pensé: importar una carpeta nunca la mueve. Eso es deliberado - el objetivo completo es que nada reorganice físicamente los archivos sin autorización. Pero un simple listado de carpetas no tiene forma de saber “esta carpeta ya está registrada en la base de datos.” Solo ve una carpeta, sentada exactamente donde siempre estuvo, indistinguible de una que nunca se tocó. Detectar algo y actuar sobre algo eran dos operaciones completamente separadas que no se comunicaban entre sí, y yo solo había construido un lado de esa conversación.
Misma forma de solución que el primer error: la capa que ya tiene abiertos tanto los resultados del escaneo como la base de datos revisa cada candidato contra lo que ya está registrado, y descarta en silencio los que ya lo están. El escáner genérico sigue sin necesitar saber nada sobre bases de datos.
Lo que realmente demostró que esto funcionó
Ambos eran el tipo de error que una prueba simulada pasaría por alto sin más, porque un mock solo devuelve lo que se le indicó que devolviera - no puede descubrir que las suposiciones sobre “carpeta vacía” o “ya importada” no coinciden con la realidad. Así que el último paso fue correr lo real: una carpeta de vault real, con dos subcarpetas reales, ejecutada a través de la app compilada real sin ninguna simulación en ninguna capa. Escanear, confirmar que aparecen ambas carpetas. Importar una de verdad. Verificar que un archivo real llegó al disco, no solo una fila en la base de datos. Escanear de nuevo, confirmar que la importada desapareció y la otra no. Recargar el panel, confirmar que el proyecto importado está ahí como una tarjeta real y clicable.
Cada uno de esos pasos era una oportunidad para que alguno de los dos errores siguiera al acecho. Ninguno lo estaba, al final - pero no habría confiado en eso sin verlo pasar de verdad.
Lecturas relacionadas
Dos notas que nadie vio jamás
Greenhouse guardaba fielmente una nota de captura y una nota de traspaso, y no mostraba ninguna de las dos: una no tenía campo en el tipo de wire, la otra tenía un comando funcional que nadie llamaba.
Agregar un menú nativo de macOS a Greenhouse rompió Cmd+Q, y mi harness de pruebas tampoco pudo presionar Cmd+N
set_menu reemplaza el menú por defecto, no lo extiende, y se lleva con él Quit, Hide y todos los atajos de Edit. Después resultó que el endpoint de actions de WebDriver no podía presionar una tecla.
Enseñarle a un gestor de proyectos a reconocer una sesión de Logic Pro
Los archivos .logicx no son archivos, son bundles, y el filtro que ocultaba la basura de .DS_Store también ocultaba cada proyecto de DAW. Más el clic silencioso que no hacía nada y engañó a un bucle de reintento.