CI verde no significa producto cerrado
Un sistema no está terminado cuando el código compila, ni cuando el PR se mergea, ni cuando alguien dice “listo, eso ya quedó”. Está terminado cuando existe evidencia real de que funciona en el ambiente correcto.
De “parece resuelto” a “podemos demostrarlo”
El reto no era solo construir Hub. Era cerrarlo con evidencia.
Hub no era una pantalla aislada. Tocaba frontend, backend legacy, nueva API, autenticación, CORS, Sanctum, Google Classroom, workflows de deploy y staging real. Es decir: la receta perfecta para que un error se disfrace de cualquier cosa.
Antes
- Errores tratados como “un bug de Hub”.
- Confusión entre código, deploy y ambiente.
- Validaciones locales con demasiada fe.
- Cierre declarado por sensación, no por evidencia.
Después
- Gaps clasificados por tipo y riesgo.
- Specs usadas como contrato de trabajo.
- Harness, CI, deploy y smoke como cadena verificable.
- Cierre declarado solo cuando el ambiente lo demuestra.
Producto multi-superficie
Hub no fallaba en una sola capa. Ese era el chiste.
Cuando un producto toca tantas superficies, los errores rara vez llegan con gafete. Un fallo puede parecer frontend y ser backend. Puede parecer autenticación y ser configuración. Puede parecer código roto y ser un deploy que nunca publicó el último build.
Sin una metodología clara, lo fácil era caer en parches rápidos. SoftOS ayudó precisamente a evitar eso: no a correr más, sino a pensar mejor antes de meterle mano a cosas que ya estaban funcionando.
- Frontend del estudiante
- Backend legacy
- API V2
- Sanctum
- Google Classroom
- Staging real
No todo gap es un bug. A veces el bug es no saber qué tipo de problema tenemos.
Orquestación
Separar el problema antes de resolverlo.
El rol de orquestación fue clave porque no se trataba solo de “hacer cambios”. Se trataba de decidir qué tipo de problema teníamos delante.
Durante el proyecto aparecieron migraciones que no corrieron en staging, columnas faltantes, rutas no publicadas, errores por scopes, tests desactualizados, lint roto, timeout SSH y smoke autenticado pendiente. Todo eso junto suena a incendio. Separado, empieza a ser gobernable.
Código
Cambios pequeños, específicos y asociados a un gap real. Menos cirugía con motosierra, más bisturí con intención.
Ambiente
Configuración, migraciones, CORS, Sanctum y deploy no se mezclaron en una sola bolsa llamada “algo está raro”.
Evidencia
Cada cierre debía dejar rastro: commit, workflow, conclusión, deploy y validación. La fe se deja para otros contextos.
Specs sin burocracia
Documentar no es escribir por deporte.
Una de las mejores decisiones fue revisar las specs existentes antes de crear nuevas. Ya había contratos claros para migración a API V2, readiness de publicación, Classroom y hardening frontend.
La regla fue simple: si el gap ya estaba cubierto por una spec aprobada, no se creaba otra. Si el cambio alteraba deploy, CI o comportamiento transversal, ahí sí valía abrir la conversación.
Eso mantuvo el proceso liviano sin perder gobernanza. Porque sí: se puede tener orden sin convertir cada decisión en un comité con acta, café frío y ganas de renunciar.
Harness
La evidencia técnica también necesita escenario.
Los harness más útiles fueron los que produjeron evidencia objetiva. Ejecutar comandos con el runtime correcto evitó falsos positivos del entorno local, especialmente en frontend.
python3 ./flow repo exec lms-frontend-v2 -- pnpm lint
python3 ./flow repo exec lms-frontend-v2 -- pnpm typecheck
python3 ./flow repo exec lms-frontend-v2 -- pnpm test
python3 ./flow repo exec lms-frontend-v2 -- pnpm build
GitHub Actions aportó evidencia remota. Route contract volvió inspeccionable el estado del backend. Y los smoke checks ayudaron a validar disponibilidad, aunque dejaron una lección clara: un health check público no reemplaza un smoke autenticado.
CI verde no significa staging actualizado.
Uno de los momentos más importantes del proyecto fue descubrir que el código estaba bien, el CI estaba verde, pero demo-hub no tenía el último build por un timeout SSH durante rsync. Bello. Trágico. Muy ingeniería.Cierre real
Desde ahí, “listo” dejó de ser una opinión.
El arreglo no fue cambiar código. Fue reintentar el workflow y confirmar que el deploy exitoso correspondía al commit correcto.
Ese detalle cambió la forma de declarar cierre. Ya no bastaba con “pasó local”, “se ve bien” o “debería estar publicado”. El estado tenía que decir explícitamente qué se había validado y dónde.
Commit local
Qué se cambió realmente en el entorno de trabajo.
Commit remoto
Qué llegó al repositorio y con qué referencia verificable.
CI
Qué workflow corrió, con qué conclusión y sobre qué commit.
Deploy
Qué ambiente fue actualizado y si corresponde al build esperado.
Smoke
Qué comportamiento fue validado como usuario real, no solo como endpoint feliz.
Calidad de código
SoftOS redujo el impulso de tocarlo todo.
Cuando apareció un error, no se asumió automáticamente que había que modificar medio sistema. Primero se buscó evidencia. Eso protegió áreas estables y evitó convertir cada síntoma en una refactorización disfrazada.
El fix de lint en SocialAuthCallback.tsx fue pequeño, pero los tests revelaron
algo más profundo: las expectativas del router seguían pensando en un modelo viejo basado
solo en roles, mientras el producto ya usaba app_access.
Los tests fallidos no se trataron como ruido. Se revisó si representaban una regresión o si estaban desactualizados. El resultado fue mejor: los tests quedaron alineados con el comportamiento actual.
Retrospectiva
Qué repetiría y qué ajustaría.
La metodología funcionó porque mantuvo foco, redujo cambios innecesarios y permitió cerrar gaps con precisión. Pero también dejó claro dónde había espacio para endurecer el sistema.
Lo que haría igual
- Usar specs existentes antes de crear nuevas.
- Exigir evidencia por cada cierre.
- Separar código, deploy e infraestructura.
- Reportar commits y run IDs.
- No tocar áreas fuera del gap.
- Validar staging con smoke real.
Lo que mejoraría
- Automatizar más el smoke autenticado.
- Conectar mejor quality gates y deploy.
- Documentar cuándo staging usa deploy manual o automático.
- Evitar que un deploy publique si los gates relevantes fallan.
- Dejar excepciones explícitas, no implícitas.
Conclusión
Construir buen software no es solo escribir buen código.
Es construir un sistema de trabajo donde cada decisión deja rastro. Donde cada avance se puede verificar. Donde el equipo no depende de intuición, sino de evidencia.
Un proyecto está cerrado cuando puede demostrarse, no cuando parece resuelto.
En Hub, SoftOS convirtió esa idea en práctica diaria. Y honestamente, esa es la diferencia entre desarrollar producto real y jugar a que todo está bien porque el check salió verde.
¿En su equipo cómo declaran que algo está realmente cerrado?