Back to all posts

1,3 millones de líneas y 630 PR por semana: cómo mantenemos sana una base de código vibe-coded

1,3 millones de líneas y 630 PR por semana: cómo mantenemos sana una base de código vibe-coded

En julio de 2026, Robert C. Martin escribió que ya no lee el código que producen sus agentes de programación.

La afirmación llamó mucho la atención. El resto de su publicación importa más para entender cómo trabaja. Martin rodea a los agentes de pruebas unitarias, pruebas de aceptación en Gherkin, procedimientos de QA, pruebas de mutación, comprobaciones de cobertura y métricas de calidad. El código se gana su confianza al atravesar ese sistema.

Unos meses antes había planteado algo similar. En lugar de inspeccionar la implementación, mira la cobertura de pruebas, la estructura de dependencias, la complejidad ciclomática, el tamaño de los módulos y los resultados de las pruebas de mutación. Cuando algunos lo interpretaron como renunciar por completo a la revisión, lo aclaró: «Reviso muchísimo, solo que no el código».

Sus comentarios describen un problema práctico del desarrollo de software con fuerte presencia de IA. Los agentes de programación pueden producir cambios más rápido de lo que las personas pueden leerlos. Cuando el volumen de código generado supera la capacidad de revisión del equipo, la inspección línea a línea no puede seguir siendo la única fuente de confianza.

En vm0 llevamos ocho meses lidiando con el mismo problema. La mayor parte de la implementación de nuestro repositorio la escriben agentes — vibe coding, en el término popular — mientras seis ingenieros siguen siendo responsables de lo que ese código hace en producción.

La versión corta

vm0 es una base de código vibe-coded: los agentes escriben la mayor parte de la implementación y seis ingenieros responden por lo que hace en producción. A los ocho meses el repositorio tiene 1.329.170 líneas y en una sola semana se fusionaron 630 pull requests. Cinco mecanismos sostienen la carga de calidad que la revisión línea por línea ya no puede sostener sola.

  • Entornos convergentes. Ingenieros y agentes trabajan en el mismo dev container, y cada pull request puede tener su propia rama de base de datos. Un comando que funcionó para un agente funciona para una persona.
  • Restricciones ejecutables. TypeScript estricto, unos 135 módulos de contrato de API tipados, Oxlint, ESLint y reglas arquitectónicas, con CI que no acepta advertencias. Una regla que se puede comprobar mecánicamente no se deja a la revisión.
  • Pruebas en los límites. Un trofeo de testing en lugar de una pirámide: pruebas de integración a través de límites públicos de módulo, PostgreSQL y migraciones reales, mocks solo en sistemas externos. El código de pruebas es cerca del 36 por ciento del repositorio.
  • Bucles de retroalimentación completos. Los agentes levantan la aplicación y la base de datos, ejecutan migraciones y manejan un navegador real; luego reportan los comandos, la ruta probada y capturas. La mediana de fusión de un pull request ronda los 53 minutos.
  • Limpieza continua. Knip elimina código muerto de forma determinista, workflows diarios retiran el AI slop que ningún linter sabe nombrar, y un patrón que se repite lo suficiente pasa a ser regla de lint o restricción de tipos.

Qué significan realmente vibe coding y agentic coding

Vibe coding es pedirle código a un LLM, ejecutar lo que produce, pedir cambios y no prestar atención al código generado. La definición de Martin Fowler es deliberadamente estrecha, y subraya la idea de "olvidar que el código siquiera existe". Sirve para prototipos, software desechable y herramientas pequeñas de consecuencias limitadas.

Agentic coding, lo que Fowler llama programación agéntica, es lo que hacen los equipos cuando esperan mantener el resultado. Un agente lee el repositorio, edita archivos, ejecuta pruebas y trabaja por su cuenta durante un período largo, mientras las personas conservan la propiedad de la estructura y el comportamiento y revisan la evidencia de cada ejecución: resultados de pruebas, señales de calidad, previews y comportamiento en producción.

La diferencia no está en cuánto código escribe el modelo, sino en dónde se pone la atención humana.

Vibe codingAgentic coding
Autonomía del agentePromptear, ejecutar, volver a promptearLee el repositorio, edita, prueba, itera
Quién lee el códigoNadieLas personas leen lo que implica riesgo
Qué se verificaSi el resultado parece correctoTipos, contratos, pruebas, previews, señales de producción
Mejor encajePrototipos y herramientas desechablesSoftware con horizonte de mantenimiento
Fallo típicoCódigo que nadie entiendeVerificación demasiado débil para el volumen

Los agentes que editan un repositorio son una rama de un cambio más amplio; el lado para no desarrolladores lo tratamos por separado.

A vm0 solemos llamarlo proyecto vibe-coded porque esa expresión se volvió la forma corta de decir software escrito principalmente por IA. En los términos de Fowler está más cerca del agentic coding. Nuestros ingenieros escriben menos implementación que antes, y siguen siendo dueños de la arquitectura, del coste de mantenimiento y del comportamiento en producción.

A medida que la generación de código se aceleró, más de esa responsabilidad se trasladó al entorno de desarrollo, al sistema de tipos, a la suite de pruebas y a workflows de mantenimiento automatizados.

Ocho meses de crecimiento en una base de código vibe-coded

El repositorio de vm0 se creó en noviembre de 2025. En el momento de nuestro último informe semanal de escala de ingeniería, tenía aproximadamente ocho meses y medio.

El repositorio contenía:

MétricaCantidad
Líneas lógicas no vacías1.329.170
Líneas de producción850.913
Líneas de prueba478.257
Archivos fuente5.549
Archivos de prueba1.327
Paquetes44
Commits en la rama principal14.005

Estas cifras provienen de nuestro informe semanal de escala de ingeniería para la semana del 20 al 26 de julio de 2026, medidas directamente en el monorepo.

El código de pruebas representaba cerca del 36 por ciento de la base de código medida. Es una proporción del volumen de código, no una cifra de cobertura, pero da una idea de cuánta implementación se ha acumulado alrededor de la verificación.

A lo largo de tres semanas completas recientes, seis ingenieros hicieron 541, 640 y 631 commits respectivamente. Durante la semana del 20 al 26 de julio, GitHub registró 630 pull requests fusionadas. Seis ingenieros firmaron 556 de ellas, y la automatización de releases las 74 restantes.

La mediana de tiempo entre abrir una pull request y fusionarla fue de unos 53 minutos. El percentil 90 rondó las 7,4 horas.

A este ritmo de cambio, la revisión humana sigue siendo útil pero no puede sostener todo el sistema de calidad. Necesitamos señales independientes en varios puntos del ciclo de vida de un cambio.

Nuestro enfoque actual tiene cinco temas recurrentes: entornos convergentes, restricciones ejecutables, pruebas centradas en los límites, bucles de retroalimentación completos y limpieza continua.

Converger el entorno de desarrollo con dev containers

Muchos fallos difíciles de reproducir provienen de estado que nunca aparece en una pull request.

Un desarrollador puede tener una variable de entorno sin documentar, una herramienta instalada globalmente, un archivo de configuración antiguo o una base de datos que lleva meses corriendo. Las personas se acostumbran a esos detalles. Los agentes normalmente no pueden verlos.

Poco a poco dejamos de tratar la máquina anfitriona como el entorno de desarrollo estándar. Ingenieros y agentes trabajan dentro de un dev container. La imagen de desarrollo incluye el toolchain del proyecto, PostgreSQL, pgvector, Chromium y utilidades de automatización de navegador.

CI se ejecuta sobre imágenes de toolchain versionadas, construidas desde la misma familia de Dockerfile multietapa. Las imágenes de desarrollo y de CI cumplen propósitos distintos, y producción tiene su propia forma de despliegue. La propiedad útil es la convergencia: versiones de herramientas, dependencias y supuestos de runtime son explícitos y están versionados.

Esto nos da una expectativa clara. Los comandos que ejecuta un agente deberían ser reproducibles por un ingeniero en el mismo contenedor de desarrollo. Las comprobaciones que pasan durante el desarrollo deberían ejecutarse en CI bajo un toolchain muy próximo.

Aplicamos una idea similar a los datos. Cada vista previa de pull request puede tener su propia rama de base de datos y ejecutar migraciones y semillas reales. Un agente puede crear datos, modificarlos y repetir pruebas destructivas sin tomar prestada la base de datos de un desarrollador ni heredar estado de otra pull request.

Los cambios de entorno viajan por el repositorio. Actualizaciones de herramientas, versiones de navegador y extensiones de base de datos se revisan y propagan igual que el código de aplicación.

Hacer ejecutables los estándares de ingeniería en tipos y reglas de lint

Los estándares escritos ayudan a las personas a entender las decisiones de diseño. Hacen mucho menos por garantizar que cada cambio las siga, especialmente durante sesiones largas de agentes.

Metemos las reglas estables en el sistema de tipos, los linters y CI siempre que la regla pueda expresarse de forma fiable.

vm0 usa ajustes estrictos de TypeScript, incluidos strict y noUncheckedIndexedAccess. Algunos paquetes habilitan comprobaciones adicionales para valores sin usar y retornos implícitos.

La API usa una capa de contratos REST tipada y schema-first, construida con la maquinaria de tipos de tRPC y esquemas Zod. Drizzle conecta el acceso a base de datos con los tipos de TypeScript. En el momento de esta revisión, el repositorio contenía unos 135 módulos de contrato.

Estas decisiones no detectan decisiones de producto equivocadas. Sí sacan a la superficie la deriva de interfaces de forma temprana. Cuando cambia un campo o una respuesta, quienes lo consumen suelen fallar durante el análisis estático. El error resultante suele ser lo bastante específico como para que un agente lo aproveche en su siguiente iteración.

El linting cubre un segundo grupo de reglas. La plataforma ejecuta Oxlint, comprobaciones conscientes de tipos y ESLint, junto con reglas arquitectónicas propias del proyecto. CI no acepta advertencias. Las advertencias que pueden quedarse indefinidamente tienden a convertirse en ruido de fondo, y el ruido de fondo es fácil de ignorar tanto para personas como para agentes.

Cuando un problema se repite, consideramos dónde encaja la comprobación:

  1. ¿Puede expresarlo el sistema de tipos?
  2. ¿Puede detectarlo con precisión un linter o una herramienta estructural?
  3. ¿Requiere juicio semántico a lo largo del repositorio?

Los dos primeros dan retroalimentación rápida y determinista en cada cambio. El tercer grupo lo tratamos con los flujos recurrentes que describimos más adelante.

Acotar patrones propensos a errores en el código generado por IA

Algunas características del lenguaje tienen usos legítimos y a la vez aparecen con frecuencia en código frágil generado por agentes.

try/catch puede difuminar un límite de error. Cuando un agente se topa con un fallo, añadir un bloque catch y un fallback es una forma fácil de mantener vivo el camino actual perdiendo el error original. Mezclar .then() y .catch() de Promise con async/await dispersa el flujo de control entre varios estilos.

El useEffect de React crea un problema parecido en la gestión de estado. Suele usarse para copiar estado, sincronizar dos fuentes de verdad o codificar una dependencia de orden difícil de ver desde el modelo de datos.

La plataforma web principal restringe estos patrones por defecto. Una excepción justificada puede permanecer, con una explicación explícita al lado.

El código de producción de la plataforma web principal no contiene actualmente ningún useEffect. Usamos ccstate y otros patrones sin efectos para modelar dependencias y efectos secundarios de forma más explícita. Sigue existiendo un pequeño número de llamadas useEffect en producción en otras partes del monorepo, sobre todo en código compartido de UI y de escritorio, así que el alcance de la afirmación importa.

Estas reglas nacieron de fallos recurrentes en este repositorio. Cuando un patrón crea repetidamente el mismo problema de mantenimiento, lo movemos de guía de revisión a restricción ejecutable.

Probar en los límites de los módulos: un trofeo de testing, no una pirámide

vm0 no sigue una pirámide de pruebas convencional. Nuestra guía de testing describe un trofeo de pruebas: análisis estático en la base, pruebas de integración como capa dominante y un número reducido de pruebas end-to-end para los recorridos de usuario críticos.

Las pruebas unitarias son relativamente poco frecuentes. Las usamos de forma selectiva para lógica sensible a la seguridad, algoritmos y máquinas de estado. La mayor parte del comportamiento de negocio se prueba a través del límite público de un módulo.

Las pruebas de API llaman a la aplicación real a través de sus contratos. Los datos de prueba se preparan mediante endpoints de producción cuando resulta práctico, y las aserciones se hacen sobre el comportamiento público. Las pruebas evitan meter la mano directamente en un servicio interno o modificar tablas de la base de datos, porque eso las acopla a la implementación actual.

La infraestructura interna se mantiene real siempre que el coste sea razonable:

  • PostgreSQL y pgvector
  • migraciones de base de datos
  • el sistema de archivos
  • servicios internos
  • mocks en los límites con sistemas externos

Estas pruebas de integración corren más lentas que las unitarias muy aisladas y requieren un entorno más completo. A cambio, reducen la distancia entre «la prueba pasó» y «la aplicación puede realizar esta operación con una base de datos real».

Las pruebas de límites dejan margen para grandes refactorizaciones internas. Un agente puede reorganizar módulos, dividir un servicio o cambiar la capa de acceso a datos mientras el comportamiento público sigue protegido.

Uncle Bob prefiere otra mezcla, con uso intensivo de pruebas unitarias, Gherkin y pruebas de mutación. El principio compartido es la verificación independiente. El proceso que generó el código no debería ser la única fuente que afirme que ese código funciona.

Dar a los agentes de código un bucle de retroalimentación completo

Nuestras primeras ejecuciones con agentes de programación terminaban a menudo con un informe familiar: el código se cambió y TypeScript pasa; por favor, arranca la aplicación y revisa la página.

Eso deja la mitad del bucle de desarrollo en manos del ingeniero. Alguien todavía tiene que preparar una base de datos, levantar los servicios, abrir un navegador, crear datos, observar el fallo y describírselo de vuelta al agente.

Los agentes ya tienen suficiente entorno de desarrollo para hacer más de ese trabajo. Pueden arrancar la aplicación y la base de datos, ejecutar migraciones, crear datos de prueba, visitar una vista previa de pull request y realizar interacciones reales de navegador.

La verificación en navegador detecta una clase de problemas que las comprobaciones de tipos y las pruebas de API no cubren bien: navegación rota, estados de carga que nunca terminan, errores de permisos que solo aparecen en un flujo completo y regresiones visuales.

Al final de una ejecución, el agente informa de los comandos que ejecutó, el camino que probó y lo que observó. Para cambios de interfaz, puede incluir capturas de pantalla. Un ingeniero puede inspeccionar esa evidencia antes de decidir si abre la vista previa en persona.

Una captura no es una prueba y no demuestra la ausencia de otros fallos. Lo que hace es abaratar la reconstrucción del contexto del agente. Para un cambio pequeño de interfaz, unos pasos reproducibles y una captura final son mucho más útiles que un mensaje diciendo que el cambio «debería estar arreglado».

La calidad del trabajo de un agente depende en gran medida de la retroalimentación que pueda obtener sin esperar a una persona.

Mantener las ramas cortas con trunk-based development

La generación rápida de código puede producir un gran inventario de ramas.

Las ramas de funcionalidad de larga vida acumulan conflictos de fusión, trabajo duplicado y contexto obsoleto. A medida que las pull requests crecen, la revisión se vuelve más difícil y lenta. Usamos desarrollo basado en tronco para mantener las ramas cortas e integrar de forma continua alrededor de main.

Nuestras reglas de la rama principal exigen:

  • pull requests para los cambios
  • historial lineal y merges con squash
  • una cola de fusión
  • comprobaciones de Turbo, Rust y seguridad
  • sin evasión rutinaria de las barreras obligatorias

La automatización sigue el mismo camino. Un agente puede crear una pull request, y algunas tareas de mantenimiento de bajo riesgo pueden habilitar la fusión automática, pero el cambio sigue pasando por CI y la cola de fusión.

El tamaño y la vida de las pull requests ayudan a explicar cómo pudieron fusionarse 630 en una semana. Un cambio pequeño carga menos contexto, es más fácil de verificar y tiene menos probabilidades de chocar con el trabajo de producto o con otra reparación automatizada.

Knip como recolección de basura del repositorio: eliminar código muerto

La generación de código añade archivos y abstracciones de forma natural. Borrar suele necesitar un prompt aparte.

Tras una refactorización, pueden quedar archivos antiguos en el repositorio. Eliminar una funcionalidad puede dejar atrás exportaciones, dependencias y puntos de entrada. Estos restos rara vez rompen pruebas, pero con el tiempo hacen la base de código más difícil de recorrer.

Usamos Knip para encontrar archivos, exportaciones, dependencias y puntos de entrada sin usar. TypeScript puede confirmar que el código es válido; Knip pregunta si sigue participando en el sistema.

Ese residuo tiene un coste añadido para los agentes de programación. El repositorio es una de sus fuentes de contexto más importantes. Un helper obsoleto o una implementación abandonada puede parecer un patrón aprobado al siguiente agente que lo lea.

Eliminar código muerto también mejora las entradas disponibles para futuras ejecuciones. Knip resuelve la parte determinista de ese trabajo lo bastante rápido como para convertirse en una comprobación de calidad habitual.

Workflows recurrentes de limpieza de AI slop

Knip y ESLint tienen límites claros. Muchas formas de degradación requieren contexto de proyecto y juicio semántico.

Usamos «AI slop» como etiqueta práctica para ese residuo: fallbacks innecesarios, abstracciones duplicadas, pruebas que esquivan un límite público o ramas defensivas para estados imposibles. Cada caso puede parecer inofensivo. En conjunto, hacen el repositorio más difícil de entender y dan malos ejemplos a los futuros agentes.

Varios flujos recurrentes en vm0 rastrean estos patrones.

Una limpieza diaria de AI slop busca residuo nuevo y selecciona un pequeño conjunto de correcciones de alta confianza y bajo riesgo. Otros flujos inspeccionan pruebas de API que meten la mano en servicios internos, antipatrones de React y ccstate, y deuda técnica que puede tratarse con seguridad.

Cada flujo mantiene sus cambios acotados. Abre una pull request y luego se apoya en las comprobaciones de tipos, reglas de lint, pruebas y cola de fusión habituales. Una pull request configurada para fusión automática sigue teniendo que pasar las mismas barreras.

Flujo automatizado de mantenimiento del repositorio, del escaneo a CI y la fusión, con reparación en caso de fallo

Los flujos no intentan liquidar toda la deuda técnica de una pasada. Un lote diario pequeño es más fácil de verificar y menos disruptivo que una gran limpieza cada varios meses.

Cuando un flujo recurrente encuentra el mismo patrón con suficiente frecuencia, consideramos mover la comprobación a ESLint, Knip o el sistema de tipos. El flujo semántico funciona como lugar donde observar y afinar la regla antes de convertirla en una comprobación determinista más barata.

Estos workflows de vm0 recurrentes se ejecutan según un calendario.

Convertir tests inestables en reparaciones automáticas

Otro grupo de flujos parte de los fallos de GitHub Actions.

Cuando una prueba falla en la rama principal o en la cola de fusión, un flujo lee los logs, busca indicios de fragilidad y examina reintentos, tiempos y factores del entorno. Si la evidencia respalda una reparación concreta, actualiza la prueba o la implementación, abre una pull request y vuelve a ejecutar el camino completo de CI.

Que pase en un reintento no vuelve inofensivo el fallo original. Los equipos que dependen del botón de reintentar van perdiendo la confianza en las builds rojas. Cuando eso ocurre, las comprobaciones fallidas se convierten en otra forma de ruido de fondo.

Un flujo de reparación automatizado convierte un fallo intermitente en un cambio de código trazable. El diagnóstico, el parche y la verificación quedan visibles en la pull request. Los ingenieros pueden inspeccionar los cambios de más riesgo, mientras que las correcciones acotadas con evidencia sólida pueden avanzar por la cola de fusión.

Nuestro sistema de calidad tiene actualmente tres capas amplias:

EtapaMecanismosPreocupaciones típicas
Al escribirTypeScript, contratos, Drizzle, ESLinterrores de tipos, deriva de interfaces, patrones de código conocidos
Antes de fusionarKnip, pruebas de integración, bases de datos reales, vistas previas, cola de fusióncódigo muerto, comportamiento de módulos, resultados completos en runtime
Después de fusionarflujos de vm0 programados y dirigidos por eventosAI slop, antipatrones semánticos, pruebas frágiles, deriva arquitectónica

Las capas se alimentan entre sí. Los problemas hallados por los flujos pueden convertirse en reglas estáticas. Los fallos encontrados en CI o producción pueden convertirse en pruebas y en nuevas guías de ingeniería.

Ejecutar agentes de forma continua no es gratis, y hemos escrito aparte sobre cómo bajar ese coste.

Dónde va la atención humana al revisar código generado por IA

Los ingenieros de vm0 siguen leyendo código, sobre todo en cambios arquitectónicos, trabajo sensible a la seguridad, pagos y migraciones de datos. No hemos convertido «nunca leas el código» en una regla del equipo.

Lo que cambió es el reparto de la atención. Leer código es una señal más entre contratos, límites de pruebas, comportamiento de las vistas previas, capturas de pantalla, métricas de calidad y diagnósticos de los flujos.

Varias decisiones siguen requiriendo criterio experimentado:

  • si el requisito está completo
  • dónde deberían situarse los límites de los módulos
  • qué fallos son recuperables
  • cuánto impacto de negocio podría generar un defecto
  • si un modelo de seguridad es adecuado
  • qué nuevo patrón de fallo no cubren las reglas actuales

Los ingenieros también mantienen el entorno que rodea a los agentes. Cuando un problema se repite, decidimos si añadir una restricción de tipos, una regla de lint, una prueba o un flujo recurrente. El sistema de desarrollo se ha convertido en un artefacto de ingeniería importante por derecho propio.

El código legible sigue importando. El próximo lector puede ser un ingeniero u otro agente. El código enredado consume más contexto, amplía el alcance de futuros cambios y hace la verificación menos fiable.

Un cambio parecido ocurrió en diseño, donde design-as-code llevó las decisiones visuales al mismo repositorio y al mismo circuito de revisión.

Seguridad y los cambios que no se aceleran

La velocidad no se reparte por igual. En vm0 hay una lista corta de cambios que van a su propio ritmo: trabajo sensible a seguridad, pagos, migraciones de datos y decisiones de arquitectura. Un ingeniero los lee línea por línea, sin importar quién o qué los escribió.

El riesgo de seguridad del código generado por IA, según nuestra experiencia, tiene menos que ver con vulnerabilidades exóticas que con código plausible del que nadie se hace cargo. Los controles que importan son los de siempre, aplicados con constancia:

  • Las pruebas unitarias, que por lo demás usamos poco, se usan de forma deliberada para lógica sensible a seguridad, algoritmos y máquinas de estado.
  • Las pruebas mockean solo en los límites de sistemas externos. La infraestructura interna se mantiene real, así un cambio que rompe un contrato interno falla en CI y no en producción.
  • Los agentes trabajan dentro del dev container contra una rama de base de datos por pull request, no en la máquina de un desarrollador ni en una base compartida.
  • La merge queue y los checks obligatorios no tienen atajo rutinario, tampoco para un pull request que abrió un agente y marcó para fusión automática.
  • try/catch está restringido por defecto, para que un fallo no quede tapado por un fallback que un agente añadió con tal de que el camino actual siguiera funcionando.

El manejo de credenciales es un problema de diseño aparte con su propia respuesta: describimos el patrón de broker que mantiene los tokens fuera del alcance de un agente en su propio artículo.

Nada de esto vuelve seguro el código generado por sí solo. Reduce el conjunto de cambios en los que una decisión humana es el único control, y deja ese conjunto explícito.

Lo que estas cifras no muestran

El informe semanal demuestra la escala del repositorio y la velocidad de entrega. Por sí solo no demuestra fiabilidad en producción.

Evaluar el efecto sobre la calidad en runtime exige disponibilidad, tasas de error en producción, recuento de incidencias, tasa de fallo por cambio, frecuencia de rollback y tiempo medio de recuperación. Una ejecución verde de CI describe una parte del proceso de entrega.

Seguimos reuniendo esas medidas de resultado. Las prácticas de ingeniería explican cómo un sistema gestiona el riesgo; los datos de producción muestran cuán bien funciona esa gestión.

Preguntas frecuentes

¿Qué es el vibe coding? Vibe coding es pedirle código a un LLM, ejecutar lo que devuelve, pedir cambios y no leer el código generado. La definición de Fowler es estrecha a propósito: la persona debe "olvidar que el código siquiera existe". Encaja con prototipos, software desechable y herramientas de consecuencias limitadas.

¿Qué es el agentic coding? El agentic coding es una forma de desarrollo asistido por IA de ejecución más larga, en la que un agente lee un repositorio, edita archivos, ejecuta pruebas e itera por su cuenta durante un período extenso. Las personas siguen siendo dueñas de la arquitectura y el comportamiento, y revisan la evidencia de la ejecución en vez de cada línea escrita.

¿Cuál es la diferencia entre vibe coding y agentic coding? La atención, no la autoría. En el vibe coding el código nunca se inspecciona. En el agentic coding el agente trabaja por su cuenta mientras los ingenieros revisan la evidencia alrededor: resultados de pruebas, señales de calidad, previews y comportamiento en producción. A vm0 se le suele llamar vibe-coded; en los términos de Fowler es agentic coding.

¿Qué es el AI slop? AI slop es el residuo que deja el código generado por IA: fallbacks innecesarios, abstracciones duplicadas, pruebas que esquivan un límite público, ramas defensivas para estados imposibles. Cada caso parece inofensivo. En conjunto vuelven el repositorio más difícil de entender y dan malos ejemplos al siguiente agente.

¿Cómo se revisa código generado por IA con 630 pull requests por semana? No línea por línea. En vm0 la revisión humana va donde hace falta criterio: arquitectura, trabajo sensible a seguridad, pagos, migraciones de datos. El resto lo sostienen mecanismos: tipos estrictos y contratos, pruebas de integración en límites de módulo, bases de datos reales en previews por pull request, verificación en navegador, Knip y una merge queue sin atajos rutinarios.

¿Cuáles son las buenas prácticas del vibe coding a escala? Cinco se han sostenido en vm0 durante ocho meses: converger el entorno de desarrollo para que agentes y personas ejecuten los mismos comandos; hacer los estándares ejecutables en tipos, linters y CI en vez de documentos; probar en los límites de módulo contra infraestructura real; dar a los agentes un bucle de retroalimentación completo, navegador incluido; y limpiar de forma continua en lugar de en pasadas grandes y esporádicas.

¿Qué riesgos de seguridad tiene el código generado por IA? El riesgo habitual no es una vulnerabilidad exótica sino código plausible del que nadie se hace cargo. vm0 mantiene en revisión humana el trabajo sensible a seguridad, los pagos y las migraciones de datos, usa pruebas unitarias de forma deliberada para esa lógica, mantiene real la infraestructura interna en las pruebas, restringe patrones como try/catch que tapan fallos y no permite saltarse los checks obligatorios.

¿El código generado por IA crea deuda técnica? Crea un tipo concreto: código que aún compila y pasa las pruebas pero ya no participa en el sistema, más un residuo semántico que ningún linter sabe nombrar. Knip elimina la parte determinista. Los workflows recurrentes se ocupan del resto en lotes diarios pequeños, y un patrón que se repite lo suficiente pasa a ser regla de lint o restricción de tipos.

¿Cuánto del código de vm0 lo escribe la IA? La mayor parte de la implementación. En la semana del 20 al 26 de julio de 2026, seis ingenieros firmaron 556 de los 630 pull requests fusionados y la automatización de releases el resto, y los agentes escribieron el grueso del código dentro de esos pull requests. Lo que los ingenieros conservan es la arquitectura, las restricciones y el comportamiento en producción.

¿Qué es un trofeo de testing y por qué no una pirámide? Un trofeo de testing pone el análisis estático en la base, las pruebas de integración como capa dominante y unas pocas pruebas end-to-end arriba. vm0 lo usa porque las pruebas escritas a través del límite público de un módulo siguen protegiendo el comportamiento mientras un agente reorganiza la implementación por debajo, algo que una capa grande de pruebas unitarias no logra.

¿Cómo se encuentra código muerto en un repositorio escrito por IA? La generación de código añade archivos y abstracciones; borrar suele requerir una instrucción aparte. vm0 ejecuta Knip como comprobación regular para encontrar archivos, exports, dependencias y puntos de entrada sin uso. TypeScript confirma que el código es válido; Knip pregunta si todavía participa en el sistema, que es la pregunta que importa con el código muerto.

¿Es seguro llevar a producción código vibe-coded? Depende de qué lo verifica, no de quién lo escribió. Las señales que exigimos no han cambiado: tipos y contratos, pruebas a través de límites públicos, infraestructura real y una pipeline que tiene que estar en verde. Las cifras de este artículo describen escala del repositorio y velocidad de entrega; disponibilidad, tasas de error y change-failure rate responden a la pregunta de producción, y seguimos reuniéndolas.

Ocho meses después

Ocho meses es demasiado pronto para declarar un método definitivo. Los modelos, las herramientas de agentes y el repositorio siguen cambiando, y nuestras reglas y flujos cambian con ellos.

Un desplazamiento ya está claro. A medida que la generación de código se aceleró, el entorno, las restricciones, las pruebas y el sistema de retroalimentación asumieron más carga de calidad. Los ingenieros pasan menos tiempo escribiendo implementación y más definiendo comportamiento, diseñando límites y mejorando la verificación.

La base de código de vm0 seguirá creciendo. Knip elimina el residuo determinista. Las reglas estáticas bloquean patrones de fallo que ya entendemos. Las pruebas de integración protegen el comportamiento de los módulos. Los flujos recurrentes tratan la degradación que aún no sabemos expresar mecánicamente.

El código sigue importando. Ahora usamos más evidencia ejecutable por máquina para decidir si un cambio pertenece a la rama principal, y si su implementación debería permanecer en el repositorio.

Stay in the loop

// Get the latest insights on AI teammates and collaboration.

SubscribeJoin Discord