# Cómo revisar código generado por IA: las pruebas verdes no bastan

> Canonical: https://vxi.me/es/posts/vibe-coding-ai-code-review-evidence-gates/
> Locale: es-es
> Published: 2026-10-25
> Updated: 2026-10-25
> Markdown: https://vxi.me/es/posts/vibe-coding-ai-code-review-evidence-gates.md

<figure class="ai-review-evidence-hero not-prose" lang="es-es">
<picture><source media="(prefers-reduced-motion: reduce) and (max-width: 640px)" srcset="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-evidence-gates.mobile.still.es-es.svg" type="image/svg+xml"><source media="(prefers-reduced-motion: reduce)" srcset="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-evidence-gates.still.es-es.svg" type="image/svg+xml"><source media="(max-width: 640px)" srcset="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-evidence-gates.mobile.es-es.svg" type="image/svg+xml"><img src="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-evidence-gates.es-es.svg" alt="Tres versiones de código superaron 8/8, 10/10 y 12/12 pruebas principales. La revisión independiente halló cuatro clases de defectos y rechazó cuatro sondas adicionales. Solo offline." width="1200" height="700" loading="eager" fetchpriority="high" decoding="async" style="display:block;width:100%;height:auto"></picture>
<figcaption style="font-size:0.8rem;line-height:1.5;opacity:.78;margin-top:.35rem">Tres versiones distintas y sus resultados de revisión independiente. Las pruebas verdes no autorizan producción.</figcaption>
</figure>

Vibe Coding acelera la producción de código, pero no reduce automáticamente el trabajo de revisión. Un LLM puede entregar un diff ordenado con rapidez. Una explicación convincente o una suite verde no demuestra por sí sola que la implementación sea segura para producción.

El caso es un validador previo a la compilación para los SVG de terminal animados de este programa del blog. Comprueba reglas XML/CSS limitadas, rutas y SHA-256 del manifest, y que los artículos de ocho idiomas referencien imágenes visibles. Un SVG canonical fijo sirve como caso positivo. Los cuatro defectos se encontraron en pruebas aisladas antes de la fusión; la evidencia se limita al validador offline.

La suite inicial pasó **8/8**, pero una revisión independiente halló dos aceptaciones inseguras. Tras el primer arreglo pasó **10/10**, y después se encontraron dos defectos más. La versión final fijada pasó **12/12 pruebas principales**; cuatro sondas de ataque adicionales fueron rechazadas por separado. Tres archivos JavaScript también pasaron node --check.

El método tiene cinco pasos: fijar alcance e invariantes; construir contraejemplos mínimos; registrar RED solo si existe una ejecución fallida real; verificar de forma independiente los casos positivos y negativos sobre el commit exacto; decidir según el riesgo. Las pruebas lógicas no sustituyen la compilación ni las comprobaciones de plataforma y ejecución. Para cambios de riesgo, una ficha breve puede registrar alcance, commits Base/Head, invariantes, caso positivo, contraejemplo, comando y entorno, límites sin verificar y conclusión. El validador es un componente de build del blog, no un CLI genérico empaquetado por separado. No se ha medido ahorro de tiempo de revisión.

El repositorio público contiene únicamente contraejemplos sintéticos saneados y pruebas educativas ejecutables; no incluye el validador de producción de este programa de blog, sus arreglos ni su arquitectura interna. La secuencia 8/8 → 10/10 → 12/12 procede de la revisión offline original; las pruebas públicas reproducen los cuatro patrones de fallo, no la implementación de producción.

<a class="gh-repo-pill" href="https://github.com/vxime/ai-code-review-counterexamples/tree/74d9f12331ef4d015bf882a6e09d66e59434368b" target="_blank" rel="noopener noreferrer"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" width="18" height="18"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645.12.54 2.873.12 3.176.765.84 1.23 1.91.81 3.22.61 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606.21 2.896.015 3.286C20.565 22.092 24 17.592 24 12.297"/></svg><span>Ejemplos sintéticos saneados y pruebas reproducibles</span></a>

## ¿Por qué 8/8 pruebas aceptaron entradas incorrectas?

Una suite verde solo muestra que las entradas actuales cumplen las aserciones actuales. No prueba que todas las entradas inválidas se rechacen.

El primer contraejemplo colocó una imagen permitida y una referencia no autorizada a otro artículo en la misma línea. La lógica antigua encontraba una imagen permitida y aceptaba la línea completa. La revisión creó un SVG real bajo otro slug y añadió la referencia Markdown junto a la imagen válida en los ocho artículos localizados. El archivo existía para descartar un fallo falso por destino ausente. La implementación antigua seguía devolviendo éxito con posts_checked=8.

~~~html
<img src="/assets/terminal-demo.svg" alt="Terminal demo" width="356" height="137" /> ![foreign](../foreign/terminal-demo.svg)
~~~

El segundo contraejemplo fue una carrera del sistema de archivos. El test sustituyó un directorio padre al abrir el archivo; fuera del checkout había un SVG canonical con SHA-256 correcto. Tras convertir el directorio padre en un symlink hacia fuera, la implementación antigua leyó y aceptó el archivo externo. Se eludió la procedencia, no el hash.

La ruta Linux final abre la raíz confiable del checkout y resuelve componentes respecto a descriptores de directorio ya abiertos. Los componentes intermedios deben ser directorios y usan O_NOFOLLOW; el archivo final también rechaza symlinks. Se comprueban tipo, enlaces y tamaño, se comparan device, inode y tamaño antes/después de leer, y luego se verifica el digest. Usa Linux /proc/self/fd y falla de forma cerrada sin procfs. El alcance presupone un checkout confiable y procfs disponible, no atacantes arbitrarios con el mismo UID o privilegios de host. Consulta [Linux openat2(2)](https://man7.org/linux/man-pages/man2/openat2.2.html).

## Segunda ronda: el hash es correcto, pero el contenido no se ve

Tras el primer arreglo, 10/10 pruebas pasaron. El tercer contraejemplo se refiere a reduced motion: los fotogramas SVG empiezan transparentes y la animación los revela. Si la regla solo detiene la animación sin mostrar el último fotograma, el resultado queda en blanco.

~~~css
.f { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  #f0 { animation: none; opacity: 1; }
  #f3 { animation: none; } /* el último fotograma sigue transparente */
}
~~~

El test recalculó SHA-256, tamaño, nombre basado en contenido y manifest canonical para mantener válidas las comprobaciones periféricas. Verificó el contrato “el resultado final debe ser visible”. Consulta [MDN sobre prefers-reduced-motion](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/%40media/prefers-reduced-motion).

El cuarto contraejemplo vino de Markdown: la regex antigua contaba imágenes dentro de comentarios HTML. Al comentar la única imagen, la etiqueta seguía en el código fuente pero no aparecía en la página. Según [CommonMark 0.31.2](https://spec.commonmark.org/0.31.2/#html-blocks), una etiqueta comentada no es una imagen visible.

~~~html
<!-- <img src="/assets/demo.svg" alt="Terminal demo" /> -->
~~~

<figure class="ai-review-counterexample not-prose" lang="es-es">
<picture><source media="(prefers-reduced-motion: reduce) and (max-width: 640px)" srcset="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-counterexample.mobile.still.es-es.svg" type="image/svg+xml"><source media="(prefers-reduced-motion: reduce)" srcset="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-counterexample.still.es-es.svg" type="image/svg+xml"><source media="(max-width: 640px)" srcset="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-counterexample.mobile.es-es.svg" type="image/svg+xml"><img src="/images/posts/vibe-coding-ai-code-review-evidence-gates/ai-review-counterexample.es-es.svg" alt="Tras pasar 10/10 pruebas, una revisión independiente encontró una imagen dentro de un comentario HTML contada como visible. La versión final pasó 12/12 y rechazó cuatro sondas." width="1200" height="700" loading="lazy" decoding="async" style="display:block;width:100%;height:auto"></picture>
<figcaption style="font-size:0.8rem;line-height:1.5;opacity:.78;margin-top:.35rem">Las pruebas verdes pueden omitir contraejemplos: una etiqueta comentada no es una imagen visible.</figcaption>
</figure>

## Vincular resultados a versiones exactas

| Versión | Suite principal | Revisión independiente posterior |
| --- | --- | --- |
| Versión inicial | 8/8 superadas | Aceptaciones inseguras SEC-01 y SEC-02 |
| Versión tras el primer arreglo | 10/10 superadas | Aceptaciones inseguras SEC-03 y SEC-04 |
| Versión final revisada offline | 12/12 pruebas principales superadas | Cuatro sondas adicionales rechazadas |

La suite final incluye regresiones SEC-01 a SEC-04. Las cuatro sondas adicionales no cuentan para 12/12 y no deben sumarse como 16/16. Tres archivos JavaScript pasaron node --check, una comprobación de sintaxis, no de comportamiento.

Las dos últimas pruebas de regresión se confirmaron antes de corregir el código, pero la suite completa no se ejecutó en el commit que solo añadía pruebas. Por eso no existe un registro de 10/12 RED completo. Sí se reprodujeron aceptaciones incorrectas en el validador antiguo y la versión final pasó las pruebas principales y las sondas separadas.

Tras estabilizar la evidencia de comportamiento, reviso la complejidad: qué invariante protege cada helper, rama o configuración, si duplica lógica y si tiene consumidores reales. Menos código no significa automáticamente más simple; eliminar una protección de ruta puede reintroducir una carrera.


<!-- vxi-evidence-panel: ai-code-review-counterexamples -->

Lecturas relacionadas: [Mutation Testing](/posts/ai-generated-tests-mutation-testing/), [el límite fail-open de revisión pre-push de OpenQodex](/posts/openqodex-prepush-review-fail-open/) y [los anclajes de comentarios de Diffle](/posts/diffle-git-diff-comment-anchoring/).

## ¿Qué falta entre pruebas aprobadas y autorización de producción?

La revisión final cubrió el validador offline en Node.js v22.16.0, Linux x64: 12/12 pruebas principales pasaron, cuatro sondas adicionales fueron rechazadas, los casos positivos de SVG/manifest y las ocho asociaciones de idioma pasaron, y tres archivos JavaScript pasaron node --check.

Esto respalda una conclusión limitada: las cuatro aceptaciones incorrectas conocidas se corrigieron en ese entorno y bajo esas reglas. No demuestra que todo el blog esté listo para producción. La resistencia nativa de macOS ante escritores concurrentes maliciosos sigue sin verificarse; la compilación completa del sitio y la ejecución final de la página quedaron fuera de las pruebas offline.

La aprobación debe dividirse por riesgo: pruebas unitarias para el comportamiento cubierto, controles estáticos para patrones, build e integración para la composición, y comprobaciones de plataforma/runtime para los límites de despliegue. Si una frontera crítica sigue sin verificar, un éxito local no es preparación completa para producción.

Los contratos y contraejemplos identifican el comportamiento sospechoso; las pruebas de la versión exacta y la evidencia independiente deciden dónde profundizar. No elimina el juicio humano: convierte “parece correcto” en una decisión de revisión con evidencia, alcance y posibilidad de verificación.

## Verification context

- Level: first-party
- Verified: 2026-10-25T00:00:00.000Z
- Environment: Node.js v22.16.0 / Linux x64
- Evidence mode: mixed
- Public repository: https://github.com/vxime/ai-code-review-counterexamples
- Evidence commit: 74d9f12331ef4d015bf882a6e09d66e59434368b
- Evidence receipt: https://vxi.me/evidence/vibe-coding-ai-code-review-evidence-gates.json
