Ir al contenido
14 ago 2026·8 min de lectura

Cómo revisar código generado por IA que nadie puede leer

Aprende a revisar código generado por IA a escala con pruebas de propiedades, comparación diferencial, invariantes e inspección humana focalizada.

Cómo revisar código generado por IA que nadie puede leer

Un modelo puede producir en una tarde más código del que un equipo competente puede inspeccionar en una semana. Intentar conservar el antiguo ritual de revisión añadiendo más revisores no resuelve ese desfase. Solo crea una cola, favorece las aprobaciones superficiales y sigue sin detectar fallos repartidos entre cientos de funciones que parecen razonables por separado.

El criterio viable son las pruebas, no la cobertura visual completa. Los revisores deben demostrar que el sistema nuevo conserva el comportamiento requerido, cumple las reglas que siempre deben mantenerse y no contiene decisiones inaceptables en los pocos lugares donde el juicio humano no se puede automatizar. Leer sigue siendo necesario, pero la lectura pasa de todas las líneas a los puntos donde una línea puede alterar permisos, dinero, datos o recuperación.

Clasifica el riesgo antes de elegir el método de revisión

La cantidad de código dice muy poco sobre la cantidad de revisión necesaria. El esfuerzo debe seguir las consecuencias de una decisión equivocada y la facilidad con la que las pruebas pueden observarla. Un analizador generado con una gramática precisa puede necesitar más casos automáticos y menos lectura línea por línea que una función corta de autorización cuya intención vive en documentos de políticas y excepciones.

Empieza por dividir el cambio en superficies de comportamiento. Una superficie es un conjunto de entradas, estado y salidas que se puede probar como un solo contrato: cálculo de facturas, elegibilidad de cuentas, conversión de archivos, evaluación de permisos, reinicio de lotes o migración de bases de datos. No dividas el trabajo por número de archivos generados. Los modelos suelen repartir una decisión entre adaptadores, funciones auxiliares y tipos, mientras que un gran asignador de datos generado puede contener muy pocas decisiones independientes.

Registra cuatro datos para cada superficie: la consecuencia de un fallo, el comportamiento de referencia disponible, los invariantes aplicables y los lugares del código que ejercen autoridad. La consecuencia determina cuántas pruebas independientes hacen falta. La referencia indica si se puede hacer una comparación diferencial. Los invariantes descubren fallos incluso cuando la implementación de referencia los comparte. Los puntos de autoridad muestran dónde deben leer las personas.

Una matriz de revisión útil tiene este aspecto:

  • Cálculo fiscal: compara el servicio antiguo con ejemplos aprobados, reproduce casos, comprueba la conservación e inspecciona el redondeo y la selección de tasas.
  • Importación CSV: usa la especificación del formato y muestras de producción, genera entradas incorrectas e inspecciona los errores y los límites de recursos.
  • Comprobación de roles: crea una tabla de decisiones a partir de las políticas, prueba las denegaciones e inspecciona cada ruta que concede acceso.
  • Reinicio de lotes: reproduce el historial de trabajos, inyecta fallos, comprueba la idempotencia e inspecciona los límites de transacción.

Esta clasificación también responde si es seguro integrar código escrito por un modelo. Solo es suficientemente seguro cuando las pruebas se corresponden con la consecuencia del fallo y las diferencias sin resolver tienen responsable. Ninguna puntuación del modelo, cantidad de pruebas o confianza del revisor sustituye esa decisión. Un formateador de bajo riesgo puede pasar con propiedades y muestras. Una ruta de pagos o permisos necesita especificaciones independientes, casos adversos e inspección directa.

Escribe el contrato observable antes de leer la implementación

El revisor necesita una descripción externa del comportamiento correcto antes de abrir el código generado. De lo contrario, la implementación se convierte discretamente en su propia especificación y una estructura plausible se confunde con una intención correcta. El contrato debe describir lo que pueden observar quienes llaman al sistema: valores devueltos, cambios de estado, errores, límites temporales relevantes y efectos externos.

Extrae el contrato de fuentes que existían antes de la generación: definiciones de interfaces, manuales de operación, solicitudes y respuestas de producción, restricciones de la base de datos, datos de prueba aceptados, normativas y entrevistas con quienes gestionan las excepciones. El código antiguo es una fuente, no la única. Los comentarios pueden estar desactualizados, las pruebas pueden codificar accidentes y los operadores actuales pueden depender de comportamientos que nadie documentó.

Escribe explícitamente los casos incómodos. ¿Qué ocurre con una entrada vacía? ¿Qué zona horaria controla un cierre? ¿Un reintento vuelve a enviar un correo o reutiliza el resultado anterior? ¿Un campo ausente es distinto de un valor cero? ¿Qué regla decimal se aplica justo entre dos importes representables? ¿El orden tiene significado aunque una API diga que no? Estas preguntas causan más fallos de migración que los errores de sintaxis o de tipos.

El contrato también debe marcar los cambios permitidos. Algunas reescrituras deben conservar la salida byte por byte. Otras pueden normalizar espacios, sustituir un identificador interno o devolver un error más claro sin cambiar su categoría. Si los revisores no definen una relación de equivalencia, la herramienta de comparación informará de ruido inocuo o, peor aún, normalizará un defecto real hasta ocultarlo.

Mantén las cláusulas del contrato comprobables. «Gestiona bien las facturas» no sirve. «Para una factura aceptada, el débito contabilizado equivale a la suma de los créditos contabilizados en la moneda del libro» puede convertirse en una propiedad. «Los reintentos son seguros» es impreciso. «Repetir el mismo identificador de solicitud no produce ningún efecto externo adicional» da algo que medir al banco de pruebas.

Hazlo antes de leer porque el código generado resulta persuasivo. Tiene nombres, ramas, comprobaciones y comentarios dispuestos en formas familiares. Cuando un revisor ve una implementación ordenada, empieza a explicar por qué tiene sentido en lugar de preguntar si aplica la regla requerida. El contrato mantiene la carga de la prueba fuera del texto generado.

Las pruebas de propiedades cubren un espacio de entradas

Las pruebas de propiedades son apropiadas cuando se puede formular una regla válida para muchas entradas, pero no resulta viable enumerarlas. No demuestran que un programa sea correcto, y una propiedad débil puede aprobar un disparate. Su fuerza consiste en obligar al revisor a nombrar relaciones que los ejemplos ocultan.

Elige propiedades del dominio, no de la implementación. Las propiedades de ida y vuelta funcionan para codificadores cuando descodificar un valor válido codificado debe recuperar el original. Las propiedades de conservación sirven para dinero, inventario y recuentos de registros. La idempotencia se aplica a reintentos, normalización y actualizaciones que se comportan como conjuntos. La monotonía sirve cuando añadir un elemento elegible no puede reducir un total. Las propiedades metamórficas comparan entradas relacionadas, como reordenar registros que el contrato declara desordenados.

Una prueba de fuzzing compacta en Go para un límite de normalización podría ser así:

func FuzzNormalizeAccount(f *testing.F) {
    f.Add(" ab-123 ")
    f.Add("AB123")

    f.Fuzz(func(t *testing.T, raw string) {
        got, err := NormalizeAccount(raw)
        if err != nil {
            return
        }
        again, err := NormalizeAccount(got)
        if err != nil {
            t.Fatalf("normalized value rejected: %q", got)
        }
        if again != got {
            t.Fatalf("not idempotent: first=%q second=%q", got, again)
        }
        if strings.ContainsAny(got, " -\t\n") {
            t.Fatalf("separator survived: %q", got)
        }
    })
}

Esta prueba comprueba dos reglas reales: una normalización correcta es idempotente y la salida no contiene separadores prohibidos. Evita afirmar que todas las cadenas deben aceptarse. Eso convertiría una política de entrada desconocida en un requisito inventado. Añade otro generador para formatos de cuenta válidos si se conoce la gramática aceptada y exige éxito solo para ese generador.

La reducción de casos importa. Cuando un generador encuentra un fallo en una carga de 4.000 caracteres, el artefacto útil es la entrada más pequeña que todavía falla. Guarda ese caso reducido como un dato de regresión normal. La búsqueda aleatoria encuentra el hueco; el caso fijo evita que vuelva y hace que la revisión se pueda repetir. Conserva la semilla si el framework la proporciona, pero nunca dependas solo de ella, porque los cambios del generador o del entorno de ejecución pueden alterar la secuencia.

Desconfía de las propiedades que solo imitan el código. Comprobar que SortRecords devuelve lo mismo que otra llamada a SortRecords dice muy poco. Comprobar que la salida está ordenada, contiene el mismo multiconjunto de registros y no cambia con una segunda ordenación verifica hechos independientes. Las pruebas de mutación pueden exponer conjuntos débiles: si cambiar una comparación o borrar una rama de validación deja verdes todas las propiedades, el conjunto de pruebas no merece confianza.

Las pruebas diferenciales encuentran desviaciones olvidadas

Las pruebas diferenciales ejecutan las implementaciones antigua y nueva con las mismas entradas y comparan los resultados observables mediante una política de equivalencia explícita. Para reescribir un sistema heredado, suele ser la forma más rápida de descubrir comportamientos ocultos porque producción ya ha explorado combinaciones que un plan de pruebas recién escrito pasará por alto.

Construye el banco alrededor de un límite, no de funciones privadas. Captura una solicitud o entrada de trabajo, el estado inicial relevante, el resultado devuelto, los cambios de estado duraderos y los efectos externos. Después ejecuta ambos sistemas desde condiciones iniciales equivalentes. Sustituye relojes, fuentes aleatorias, identificadores y servicios remotos por adaptadores controlados para que el no determinismo no inunde la comparación.

Un registro de comparación debe poder inspeccionarse, no limitarse a un contador verde o rojo:

{
  "case_id": "replay-01842",
  "input_hash": "sha256:...",
  "old": {"status": "accepted", "total_minor": 1250, "events": ["invoice_posted"]},
  "new": {"status": "accepted", "total_minor": 1250, "events": ["invoice_posted"]},
  "normalizations": ["generated_id", "timestamp_within_1s"],
  "result": "equal"
}

Registra cada normalización. Si el banco elimina marcas temporales, ordena colecciones, oculta identificadores o agrupa textos de error en categorías, esa política forma parte de la revisión. Un normalizador amplio puede borrar justo la diferencia que necesitas ver. Por ejemplo, ordenar todos los arrays puede ocultar un cambio en el orden de contabilización que afecta al procesamiento posterior, mientras que comparar identificadores generados sin tratar crea fallos sin sentido.

El tráfico de producción exige una captura cuidadosa. Elimina o tokeniza los campos sensibles antes de que entren en un entorno de pruebas general. Conserva las relaciones de las que depende el comportamiento, como el mismo cliente en varias solicitudes. Una colección de ejemplos desconectados y excesivamente depurados puede parecer segura mientras pierde semántica de sesión, orden y reintento. En entornos regulados, conserva la captura, la ejecución y los artefactos dentro del perímetro aprobado.

La cobertura debe describir el comportamiento representado, no solo el número de reproducciones. Divide los casos por operación, resultado, indicadores importantes, categoría de error, forma de los datos y condición límite. Diez mil lecturas correctas no compensan la ausencia de una actualización fallida, un envío duplicado, una transición de cierre de mes o un reinicio tras una escritura parcial. Registra las particiones vacías como deuda de revisión explícita.

Ejecuta el banco continuamente durante la generación y después de las ediciones humanas. Una última reproducción detecta limpiezas bien intencionadas que cambian el comportamiento una vez terminado el trabajo del modelo. Guarda las discrepancias como registros duraderos con una resolución: defecto nuevo, defecto antiguo conservado a propósito, defecto antiguo corregido a propósito, cambio de política esperado o fallo del banco. Una discrepancia sin explicar no es un fallo de prueba que se pueda eximir; es una decisión sin terminar.

El sistema antiguo es testigo, no oráculo

Supera la revisión por líneas
El análisis completo y la reproducción cubren sistemas con más de un millón de líneas.

Coincidir exactamente con la implementación antigua puede conservar defectos, valores predeterminados inseguros y soluciones provisionales cuyo motivo original ya no existe. La igualdad diferencial demuestra compatibilidad, no corrección. Necesitas una regla independiente para cualquier comportamiento con consecuencias graves.

La distinción se hace concreta cuando el sistema antiguo acepta un estado imposible. Imagina que un proceso por lotes puede marcar una factura como pagada después de escribir el asiento contable pero antes de confirmar la referencia del pago. La reproducción de producción muestra esa secuencia, así que la reescritura la repite. Una barrera basada solo en paridad informa de éxito. Una propiedad de conservación también puede pasar porque el dinero cuadra. Solo un invariante que exija una referencia confirmada para el estado pagado revela la transición inválida.

Tampoco corrijas en silencio cada rareza. Un defecto puede haberse convertido en una interfaz. Los informes posteriores pueden esperar un redondeo inusual, los operadores pueden usar un código de error concreto para distribuir trabajo o los clientes pueden reintentar solo tras un estado determinado. Corregir ese comportamiento sin una decisión de migración puede provocar un fallo más amplio que mantenerlo temporalmente.

Usa un registro de diferencias con cinco campos: comportamiento observado, regla esperada independiente, consumidores afectados, resolución elegida y responsable. Si la versión nueva difiere deliberadamente, añade una prueba para la regla nueva y, cuando proceda, una nota de versión o un cambio operativo. Si el defecto debe mantenerse por compatibilidad, aíslalo tras una regla de compatibilidad con nombre para que futuros mantenedores no lo «limpien» por accidente.

La recomendación popular de hacer que el conjunto nuevo supere todas las pruebas antiguas es incompleta. Las pruebas antiguas son excelentes testigos del comportamiento conocido, pero cargan con los mismos puntos ciegos y supuestos erróneos del sistema. Trátalas como un conjunto de pruebas. Añade propiedades derivadas de reglas de negocio, pruebas negativas derivadas del análisis de amenazas y controles de transición derivados de las restricciones de los datos.

El revisor debe desconfiar cuando la paridad llega al 100 por ciento con demasiada facilidad. Puede que el límite sea demasiado estrecho, que los datos omitan casos difíciles o que el comparador ignore demasiado. Inspecciona una muestra de trazas antiguas y nuevas sin procesar, incluidos fallos, antes de confiar en el agregado. Las buenas pruebas siguen siendo legibles al abrirlas.

Los invariantes deben sobrevivir cada entrada y salida

Un invariante es una condición que debe mantenerse en todos los estados válidos del sistema, no una simple aserción colocada en una ruta feliz. Sitúa sus comprobaciones en los límites por donde el estado entra, cambia y sale: manejadores de API, consumidores de mensajes, confirmaciones de transacciones, importaciones de archivos, puntos de control de trabajos y serializadores.

Clasifica los invariantes por alcance. Los locales restringen un valor, como una cantidad que no puede ser negativa. Los agregados relacionan una colección, como débitos iguales a créditos. Los temporales restringen el orden, como una aprobación anterior al desembolso. Los de autoridad restringen actores, como impedir que un usuario apruebe una solicitud que creó. Los de recuperación restringen reintentos y reinicios, como un efecto duradero por token de idempotencia.

Las restricciones de la base de datos ofrecen una aplicación fuerte e independiente para ciertas reglas. Una restricción única puede impedir identificadores duplicados aunque todos los llamadores cometan el mismo error. Una clave externa evita un registro huérfano. Una restricción de comprobación puede rechazar una combinación inválida de estado y campo. Las pruebas de la aplicación deben recorrer la ruta de error resultante porque un rechazo técnicamente seguro puede convertirse en una interrupción si el trabajador reintenta para siempre.

Las máquinas de estados merecen pruebas de transición explícitas. Genera secuencias válidas y verifica que cada transición conserva todos los invariantes. Después genera una transición inválida en cada estado y exige su rechazo sin un cambio parcial. Comprobar solo el estado final no detecta daños transitorios, mensajes duplicados ni escrituras que sobreviven a una respuesta de error. Captura el estado antes y después del intento.

Coloca las aserciones de ejecución según la consecuencia. Las comprobaciones baratas sobre entradas no fiables pueden ejecutarse en cada solicitud. Una conciliación costosa entre tablas puede ejecutarse al confirmar, en un proceso paralelo o como barrera de despliegue. No elimines un invariante útil porque cuesta demasiado en la ruta con más tráfico; muévelo al punto más cercano donde aún detecte el fallo antes de que se propague.

Supervisa las infracciones por identidad, no como excepciones genéricas. La alerta debe nombrar la regla, la entidad afectada, la operación y la versión. Evita registrar la carga sensible usada para detectarla. Un recuento sin identidad no ayuda a revertir ni diagnosticar, mientras que una carga completa puede crear otra exposición de datos.

Los revisores deben preguntar quién es responsable de cada invariante. Si todos aceptan que los saldos deben conciliarse, pero ninguna prueba, restricción, comprobación en ejecución o conciliación programada lo aplica, el invariante solo existe en la conversación. Asigna al menos un control ejecutable y una respuesta clara a cada regla cuya infracción importe.

La revisión humana pertenece a los puntos semánticos decisivos

Prueba todo el árbol heredado
La plataforma lee juntos todos los lenguajes del código, incluidos COBOL y JCL mezclados.

Las personas deben leer código donde la intención no se puede inferir solo de ejemplos de entrada y salida o donde una decisión pequeña controla una gran consecuencia. Estos puntos semánticos decisivos incluyen autorización, criptografía, límites de transacción, migración de esquemas, control de concurrencia, borrado de datos, efectos externos, recuperación de errores y cada adaptador que normaliza las pruebas.

Lee todas las rutas que permiten en el código de autorización. Un amplio conjunto de denegaciones ayuda, pero el significado de una política suele depender de herencia de roles, límites entre inquilinos, autoridad delegada y comportamiento predeterminado cuando falta contexto. Revisa la fuente de la regla junto al código. Comprueba que el valor predeterminado deniega, que las decisiones en caché tienen el alcance correcto y que los registros no revelan datos protegidos.

Lee los límites de transacción y reintento como una sola unidad. Encuentra el punto donde una operación se vuelve duradera y sigue cada error que puede ocurrir antes y después. Comprueba si un reintento repite una escritura, envía un segundo mensaje u observa un estado confirmado a medias. El código generado suele gestionar cada error de forma local y razonable mientras pierde la secuencia entre funciones que provoca duplicados.

Lee el comparador y el banco con más escepticismo que una ayuda de prueba normal. Las pruebas solo son tan sinceras como el mecanismo que declara iguales dos ejecuciones. El modelo que escribió código de producción no debe ser el único autor y juez de su política de equivalencia. Una persona debe aprobar campos ignorados, tolerancias, orden canónico y asignaciones de categorías de error.

Lee los cambios de dependencias y de configuración generada. Puede que las pruebas nunca recorran una opción insegura del analizador, un permiso de red demasiado amplio, una comprobación de certificado desactivada o un grupo de trabajadores ilimitado. Inspecciona archivos de bloqueo, scripts de compilación, privilegios de contenedores, permisos de base de datos, ajustes de deserialización, tiempos de espera y límites de recursos. Estas decisiones pueden cambiar la superficie de ataque sin cambiar la salida funcional normal.

Muestrea código corriente solo después de cubrir los puntos decisivos. Usa un muestreo ponderado por riesgo: inspecciona una ruta vertical completa para varias operaciones representativas, además del código con alta complejidad, incertidumbre inusual del modelo, reparación manual repetida o poco alcance de pruebas. Muestrear líneas al azar crea apariencia de diligencia, pero rara vez sigue una decisión lo suficiente para juzgarla.

La revisión humana termina con una decisión escrita. El revisor debe nombrar qué inspeccionó, en qué pruebas confió, qué excluyó y qué riesgo residual queda. «Parece correcto» no es un registro de aprobación para un cambio generado que nadie pudo leer por completo.

Las pruebas necesitan su propia cadena de custodia

Comprueba comportamiento entre lenguajes
La plataforma analiza en paralelo todos los lenguajes de origen antes de producir la arquitectura destino.

Los cambios generados de gran tamaño necesitan un registro de revisión que conecte requisitos, pruebas, particiones de reproducción, discrepancias, hallazgos humanos y la compilación exacta revisada. Sin esa conexión, los equipos acumulan miles de resultados correctos que pueden pertenecer a commits, datos, normalizadores o versiones de dependencias distintos.

Da una identidad estable a cada artefacto. Registra la revisión de origen, la generada, las entradas de compilación, la versión del banco, la instantánea de datos, las semillas aleatorias pertinentes y la configuración del entorno que afecta al comportamiento. Calcula un hash de las entradas capturadas después de la depuración aprobada para que los revisores sepan si dos informes usaron el mismo corpus sin conservar datos sin tratar prohibidos.

Asocia cada regla del contrato con pruebas. Una regla puede tener una prueba de propiedad, una restricción de la base de datos, una partición de reproducción y una nota de inspección manual. Otra puede tener solo una aprobación manual porque la automatización no observa el juicio empresarial. Las asociaciones vacías son útiles: muestran exactamente dónde la aprobación se apoya en una suposición. Un panel lleno de contadores verdes oculta ese hueco.

Pon en cuarentena las pruebas inestables en vez de repetirlas hasta obtener verde. Registra el caso fallido, determina si el no determinismo viene del producto o del banco y corrige la causa. Repetir cambia el significado de la barrera de «la compilación pasó» a «un intento pasó», una afirmación mucho más débil. Si una prueba todavía no puede bloquear, márcala como no bloqueante y mantén visibles sus fallos.

Conserva los contraejemplos y las decisiones sobre discrepancias junto al cambio. Explican mejor el comportamiento que un comentario generado porque contienen una entrada, una observación y un resultado aprobado. Cuando una reescritura posterior cambie la misma superficie, esos artefactos serán una memoria institucional compacta que no depende de que siga presente el revisor original.

CodeHero aplica este principio durante las reescrituras heredadas comprobando el comportamiento frente al tráfico de producción registrado con un banco de paridad, mientras moderniza la arquitectura en vez de copiar la estructura antigua línea por línea. Esa afirmación solo sirve si el corpus de reproducción, la política de comparación y las resoluciones de discrepancias permanecen abiertos a revisión del cliente.

El registro debe poder reproducirlo alguien que no generó el código. Si un segundo ingeniero no puede ejecutar las comprobaciones especificadas y obtener el informe, el equipo tiene una presentación, no pruebas. La reproducibilidad también limita la dependencia de explicaciones del modelo, que pueden sonar coherentes sin corresponder a la compilación.

Las pruebas caducan cuando cambia el sistema que las rodea. Un informe de reproducción recogido antes de migrar el esquema, actualizar una dependencia o editar el comparador no aprueba la compilación posterior. Define reglas de invalidación en el registro: los cambios de código contractual repiten las propiedades afectadas, los cambios de normalización exigen revisar igualdades anteriores y los cambios de persistencia repiten las secuencias de recuperación. Así un informe que una vez estuvo verde no se convierte en permiso permanente.

Mantén las pruebas cerca de la superficie propietaria. Un informe de entrega gigantesco dificulta saber qué comprobación protege cada comportamiento y anima a aprobar el paquete como un solo objeto. Los registros por superficie permiten sustituir un componente, repetir su demostración y dejar intactas las pruebas no relacionadas. También exponen controles compartidos. Si cinco superficies dependen de un adaptador de reloj o una regla de comparación, ese componente merece inspección directa porque un error puede corromper cinco conclusiones.

Revisa el proceso de pruebas después de defectos escapados. Pregunta qué cláusula faltaba, qué generador no podía producir el caso, qué partición estaba vacía, qué invariante no existía o qué inspección humana omitió la rama decisiva. Añade el control duradero más pequeño que habría detectado esa clase de error. Pedir que los revisores lean más líneas arbitrarias aumenta el coste sin reparar el punto ciego.

La política de conservación debe corresponder tanto a la necesidad de reproducir la aprobación como a la sensibilidad de los datos capturados. Conserva contraejemplos minimizados y metadatos cuando sea posible. Restringe o elimina cargas de producción sin tratar según las reglas del cliente. Poder explicar una decisión no da permiso para conservar cada byte usado para tomarla.

La aprobación debe declarar el riesgo residual

Una reescritura generada está lista cuando el comportamiento requerido tiene pruebas independientes, las decisiones peligrosas recibieron inspección humana y la incertidumbre restante encaja en el presupuesto de fallos del sistema. Terminar no es alcanzar un porcentaje de líneas leídas. Es hacer una declaración defendible sobre lo que todavía puede fallar y cómo lo detectará o contendrá el equipo.

Configura las barreras según las consecuencias. Para un convertidor interno de poco impacto, pueden bastar ejemplos representativos, propiedades de análisis y capacidad de reversión. Para movimiento de dinero, control de acceso, registros regulados o borrado irreversible, exige fuentes contractuales independientes, pruebas negativas, aplicación de invariantes, cobertura diferencial de particiones importantes, inspección directa de puntos decisivos y una respuesta operativa ante infracciones.

No combines todas las pruebas en una sola puntuación. Un porcentaje alto de coincidencia no compensa un valor predeterminado de autorización sin revisar. Una cobertura fuerte de propiedades no compensa un comparador que oculta el orden. Una lectura cuidadosa no compensa la ausencia de pruebas de reintento. Mantén visibles las condiciones de veto para que un agregado atractivo no entierre un hueco grave.

Usa un registro de aprobación breve:

  1. Nombra la compilación, la versión del contrato y la instantánea de pruebas.
  2. Enumera las barreras necesarias y sus resultados.
  3. Enumera cada discrepancia aceptada y prueba no bloqueante.
  4. Nombra los puntos revisados por personas y a sus revisores.
  5. Indica riesgos residuales, controles de detección, límites de reversión y responsables.

Detén la entrega cuando un comportamiento de grandes consecuencias no tenga un oráculo independiente, un invariante o revisión directa. A veces la decisión honesta consiste en reducir el alcance: migrar las rutas de lectura antes que las de escritura, ejecutar decisiones en paralelo sin actuar sobre ellas o mantener una operación peligrosa en la implementación antigua hasta entender su contrato. Eso es control de ingeniería, no falta de ambición.

La salida de un modelo cambia la economía de escribir código, pero no cambia quién sufre las consecuencias de una mala entrega. Pide a los revisores que aprueben pruebas que puedan reproducir y riesgos que puedan nombrar. No les pidas que bendigan un volumen de texto que nadie puede asimilar responsablemente.

Preguntas frecuentes

¿Se puede automatizar la revisión de código generado por IA?

Gran parte de la recopilación de pruebas se puede automatizar, incluidas las propiedades, comparaciones de reproducción, comprobaciones de invariantes y particiones de cobertura. La aprobación no se puede automatizar por completo cuando la intención de una política, la autoridad, los efectos irreversibles o el riesgo aceptable requieren juicio humano.

¿Los revisores deben leer cada línea escrita por un modelo?

No. Deben leer cada punto semántico decisivo y suficientes rutas completas para juzgar la estructura, mientras las pruebas automáticas cubren un comportamiento amplio. Leer líneas aleatorias en un cambio enorme ofrece poca garantía y desperdicia atención.

¿Qué diferencia hay entre pruebas de propiedades y pruebas diferenciales?

Las pruebas de propiedades comprueban una regla que debe mantenerse para muchas entradas generadas. Las pruebas diferenciales comparan dos implementaciones con la misma entrada, por lo que detectan desviaciones pero también pueden conservar un defecto antiguo.

¿Cuánto tráfico de producción debe reproducir una prueba diferencial?

No existe una cifra universal honesta. Divide el tráfico por operación, resultado, límite, error y transición de estado, y muestra las particiones importantes sin cobertura en lugar de celebrar un total grande.

¿Basta con coincidir con la implementación antigua en una reescritura?

No. La coincidencia demuestra compatibilidad con el comportamiento observado, incluidos los defectos del sistema antiguo. Añade invariantes independientes y pruebas derivadas de políticas cuando un resultado incorrecto tenga consecuencias graves.

¿Qué caracteriza a un buen invariante para código generado?

Un buen invariante expresa una condición que debe mantenerse en todo estado válido y que puede comprobarse con independencia de la implementación. Ejemplos: asientos equilibrados, aislamiento entre inquilinos, transiciones válidas y un efecto duradero por identificador de solicitud.

¿Dónde deben centrarse las personas al revisar código de un modelo?

Céntrate en autorización, transacciones, concurrencia, borrado, criptografía, cambios de esquema, reintentos, efectos externos y el propio banco comparador. Esos lugares concentran mucho significado del sistema en relativamente poco código.

¿Cómo debe gestionar un equipo una diferencia encontrada al reproducir?

Registra el resultado antiguo, el nuevo, la regla esperada, los consumidores afectados, el responsable y la resolución elegida. Añade una prueba del resultado aprobado y nunca ocultes la diferencia en una normalización amplia o una exención sin explicar.

¿Son fiables las pruebas escritas por el mismo modelo?

Trátalas como borradores útiles, no como prueba independiente. Deriva propiedades de reglas externas, inspecciona comparadores y generadores, usa pruebas de mutación cuando sea práctico y pide a una persona que apruebe los supuestos que puedan ocultar un fallo.

¿Cuándo debe bloquearse la entrega de una reescritura generada?

Bloquéala cuando un comportamiento de grandes consecuencias carezca de pruebas independientes, una ruta peligrosa no tenga revisión directa o una discrepancia grave no tenga resolución. Reducir el alcance de la migración es más seguro que aprobar una incertidumbre sin responsable.