


Mejora una herramienta de pruebas de mutación según su código y pruebas actuales
Para modificar una herramienta de pruebas de mutación. Revisa primero el código y las pruebas actuales, conserva el orden de procesamiento y la evaluación diferida, crea mutadores sin mutantes inválidos, escribe pruebas que los detecten y sigue pasos seguros de revisión, CI y publicación.
Para usar estas reglas de IA
## Revisa el código, las pruebas y las notas de diseño actuales antes de cada cambio
Trata el árbol de código fuente, las pruebas, los esquemas, las decisiones de arquitectura y la documentación para contribuidores como la especificación vigente. No confíes en la memoria, en suposiciones antiguas ni en un patrón genérico de framework cuando contradigan la evidencia del repositorio.
Para cada función o corrección:
1. Busca ampliamente en las pruebas unitarias, de integración, de extremo a extremo, de arquitectura y de automutación más cercanas, incluidos nombres relacionados, fallos, entradas no válidas y casos límite.
2. Lee la implementación responsable para conocer el orden, los valores predeterminados, la semántica de los fallos y las restricciones de rendimiento.
3. Lee los registros de diseño citados y las discusiones del proyecto de origen cuando el código no deje clara la intención.
4. Escribe o porta un caso específico que falle antes de implementar el cambio y vincúlalo con su evidencia.
5. Documenta el motivo de los mecanismos no evidentes, los límites entre versiones y las incompatibilidades intencionadas.
Utiliza de forma coherente el glosario del proyecto. Modela una mutación como una descripción serializable que puede aplicarse en otro proceso y un mutador como una comprobación de aplicabilidad independiente más una transformación.
Traza la canalización de ejecución antes de modificarla: configuración, recopilación de código fuente y cobertura, enriquecimiento del AST, generación de mutaciones, ejecución de mutantes, análisis posterior opcional e informes son límites de responsabilidad ordenados. Si un cambio invalida una ruta, un control o una convención documentados, actualiza esa documentación en el mismo cambio.
## Respeta las reglas de la API pública, los tipos y los nombres
- El código de producción no debe depender de pruebas ni benchmarks. Coloca los auxiliares de prueba distribuidos en un espacio de nombres de pruebas explícito del lado de producción y aplica mecánicamente la dirección de la dependencia.
- Trata la API pública como una lista de elementos permitidos. Marca todo lo demás como interno, documenta los puntos de extensión y clasifica cualquier cambio en la lista como un evento de compatibilidad.
- Utiliza un `final` estricto solo en clases que nunca se simulen. Mantén técnicamente reemplazables los servicios que deban simularse, sin añadir una interfaz únicamente para simular una clase.
- Importa funciones y constantes de forma coherente. En las llamadas que puedan devolver `false`, elige una semántica de fallo explícita: usa un envoltorio seguro cuando el fallo sea excepcional y un alias inseguro con un nombre claro cuando se necesite el valor false.
- Prefiere constantes tipadas, marcadores explícitos de sobrescritura y objetos de valor inmutables. No hagas readonly una clase que memorice resultados en sus propias propiedades.
- Utiliza aserciones en tiempo de ejecución solo para invariantes que el análisis estático no pueda demostrar. El mensaje de la aserción debe identificar el defecto que implicaría un fallo.
- Haz que los nombres expresen contratos: `find*` devuelve un valor anulable, `get*` garantiza un valor, los constructores con nombre expresan significado de dominio y las excepciones describen el fallo de dominio en vez de terminar genéricamente en `Exception`.
- Reserva `Memoized*` para la reutilización invisible una vez por instancia. Utiliza `Cached*` solo cuando quienes llaman puedan observar claves, invalidación, TTL o un backend compartido.
- Haz que las clases puramente estáticas o formadas solo por constantes no puedan instanciarse. Reserva la inyección de dependencias para colaboradores con estado o IO.
- Mantén identificable el código copiado del proyecto de origen, conserva su atribución y documenta cada desviación local intencionada.
## Conserva la evaluación diferida y pasa los comandos de subprocesos como arreglos de argumentos
- Representa los valores costosos y reutilizables mediante una abstracción diferida con memoización. Un generador sin envolver es de una sola pasada y no debe rebobinarse, contarse ni almacenarse en un búfer.
- Distingue el mapeo estricto uno a uno del mapeo plano uno a varios. No permitas que nombres de métodos similares oculten cardinalidades distintas del flujo.
- Permite mutación por referencia en una ruta crítica medida solo cuando estén documentados su propietario y su efecto en el mismo objeto.
- Inyecta abstracciones de reloj y sistema de archivos en lugar de llamar directamente a primitivas de tiempo o disco. Las pruebas deben controlar los resultados del tiempo y del sistema de archivos.
- Representa los comandos de subprocesos como matrices de argumentos de texto de principio a fin. Cada elemento de la matriz es un token; nunca unas previamente un comando de shell ni supongas que se dividirá por espacios.
- Mantén un único registro explícito de servicios con getters tipados y fábricas diferidas. Quienes lo consumen no deben hacer búsquedas de servicios sin tipo y se prohíben los servicios especulativos e inaccesibles.
- Vuelve a vincular la configuración clonando el contenedor en vez de alterar el estado compartido del proceso. Extrae un builder tipado cuando un cierre de cableado se vuelva complejo.
- Combina la configuración según la semántica de cada campo: las sobrescrituras anulables usan coalescencia de null, mientras que los indicadores que cualquiera de las fuentes puede activar usan OR lógico. Unificar ambas reglas cambia el comportamiento de forma silenciosa.
- Resuelve las rutas de salida relativas respecto a la ubicación del archivo de configuración, conserva las rutas de flujo permitidas explícitamente y calcula una base de control de versiones para procesar solo los cambios que pretende la persona usuaria.
## Mantén el orden de procesamiento del AST sin alterar el árbol original
- Trata el orden de registro de visitantes como parte del algoritmo. Resuelve nombres y padres antes de sus consumidores, aplica exclusiones antes de adjuntar pruebas y restablece el estado reutilizable de los visitantes antes de cada archivo.
- Comunica la información mediante accesores tipados de atributos de nodos. Una exclusión marca un nodo como no aplicable; nunca elimina ni sustituye nodos durante el enriquecimiento.
- Adjunta de forma diferida las consultas costosas de cobertura solo a nodos aplicables. Conserva los dos niveles de evaluación diferida entre el descubrimiento de archivos de cobertura y el análisis de ubicaciones de pruebas por archivo.
- Dirige las consultas XML a través de un envoltorio seguro que tenga en cuenta los espacios de nombres. Conserva las alternativas de formato ordenadas y su justificación por versión; una limpieza no debe eliminar una rama aún compatible.
- Mantén el ejecutor de procesos en streaming. Los identificadores de worker que consumen las pruebas de usuario son valores de API exactos con base 1. El análisis posterior pertenece a la cadena de contenedores de procesos, no a ramificaciones propias del planificador.
- Conserva la semántica de las unidades en los cálculos de planificación: el tiempo dedicado a poner trabajo en cola es una duración, no un número de elementos. Libera las referencias a contenedores terminados antes de reutilizar los puestos de worker.
- Mantén separados y componibles los cambios de configuración del ejecutor de pruebas específicos de cada versión. Conserva la configuración moderna y autoritativa de cobertura, los filtros de inclusión de usuario, las rutas compatibles con glob y las formas antiguas de documento.
- Localiza un objetivo de mutación por las posiciones de los tokens y la clase del nodo. Clona el AST original antes de mutarlo, conserva los tokens originales para imprimir manteniendo el formato y deja el árbol original idéntico byte por byte.
- Trata los hashes de mutación, el orden de los campos y los atributos de posición obligatorios como contratos públicos de repetición. Copia todos los hijos y atributos al reconstruir nodos; un reemplazo válido puede ser un escalar, un nodo o una lista de nodos.
## Crea mutadores que no generen mutantes inválidos ni equivalentes
Un cambio completo de un mutador actualiza la implementación, todos los registros centrales y mapas de perfiles, el esquema de configuración, una prueba canónica y, cuando el comportamiento sea público, la documentación para usuarios.
- Mantén mínima la superficie pública del mutador: definición, nombre estable, aplicabilidad y transformación, más acceso a la configuración solo cuando el mutador sea configurable.
- Haz que la definición explique la mutación, la categoría, un diff de ejemplo y cómo puede una persona usuaria eliminar el mutante.
- En las comprobaciones de aplicabilidad, compara los identificadores del lenguaje según sus reglas reales de mayúsculas y minúsculas, y recorre los antepasados cuando importe el contexto anidado.
- Nunca generes errores de sintaxis, errores fatales garantizados, mutaciones equivalentes, bucles infinitos ni una mutación de la que ya sea responsable otro mutador.
- Cuando puedan existir solapamientos o equivalencias, explica el razonamiento y añade un caso con nombre que no produzca una mutación.
- Copia todos los hijos y metadatos al construir un nodo AST de reemplazo para que no se pierdan atributos silenciosamente.
- Ejecuta los mutadores mediante el harness de recorrido de producción. No construyas un recorrido desechable que omita el comportamiento de aplicabilidad o alcance.
- Trata la ausencia de salida esperada como una aserción explícita de no mutación y haz que los nombres de los conjuntos de datos se lean como especificaciones.
- Informa por mutador de las cantidades generadas, eliminadas, escapadas y agotadas por tiempo cuando cambie el volumen de mutaciones.
## Escribe pruebas repetibles que detecten los mutantes
- Proporciona una prueba canónica para cada clase fuente concreta y un objetivo de cobertura explícito para cada prueba.
- Clasifica las pruebas con IO como pruebas de integración y las pruebas sin IO como pruebas no de integración. Aplica el límite en ambas direcciones.
- Mantén las pruebas deterministas: utiliza rutas temporales generadas, fija la concurrencia en fixtures sensibles al orden de salida, respalda las variables de entorno y evita rutas inexistentes codificadas de forma fija.
- Utiliza proveedores de datos estáticos con nombres de casos descriptivos. Prefiere argumentos con nombre y valores predeterminados para firmas de prueba amplias, pero no compartas un proveedor entre pruebas que utilicen subconjuntos diferentes.
- Sustituye los grafos profundos de mocks por pequeños constructores inmutables o fakes. Haz que las expectativas de los mocks comprueben argumentos exactos para que las mutaciones no escapen mediante aserciones permisivas.
- Estructura el código de producción para hacer visibles las mutaciones: prefiere retornos tempranos, resultados booleanos separados y constantes con nombre a literales mágicos imposibles de probar.
- Evita argumentos predeterminados del constructor que oculten dependencias ausentes. Los valores predeterminados en proveedores de datos son aceptables cuando permiten que cada caso indique solo lo que modifica.
- Utiliza el harness de visitantes, el harness de comandos y otros fixtures del proyecto que reproduzcan el comportamiento de producción. No escribas un script desechable de exploración cuando deba existir una prueba unitaria específica.
- Un mutante escapado indica que falta una prueba o que debe reformarse el código. Discute los casos realmente imposibles de eliminar o que solo afectan al rendimiento en lugar de escribir una prueba artificiosa.
- Durante la iteración, ejecuta pruebas específicas. Antes de la entrega, ejecuta el formateador del repositorio, la revisión de arquitectura y análisis estático, los grupos de integración pertinentes y el conjunto completo autoritativo.
## Conserva la configuración por versión y las alternativas al limpiar el código
- Documenta los límites entre versiones y las escalas de alternativas junto con el comportamiento que protegen. No simplifiques una matriz de compatibilidad solo porque conozcas la forma más reciente.
- En los minilenguajes de configuración ordenados, procesa las claves por orden y deja que prevalezcan las posteriores. Un centinela false debe retirar todo lo registrado por esa clave, incluidos los perfiles anidados.
- Conserva la dirección de combinación y la deduplicación explícita al combinar ajustes. Una selección por línea de comandos puede sustituir la selección del archivo y, a la vez, conservar las reglas globales de exclusión.
- Haz que un registro sea la única fuente de verdad para el universo de mutadores compatibles y deriva de él las comprobaciones automáticas de cobertura.
- Cuando un filtro por nombre de prueba se acerque al límite de la expresión regular, pasa del filtro preciso a un superconjunto seguro y, por último, omite el filtro para ejecutar el conjunto completo. Nunca llegues a ejecutar cero pruebas.
- Conserva la regla asociada que considera correcto el resultado «no se ejecutó ninguna prueba» cuando una selección vacía sea válida.
- Tras reiniciar para retirar un depurador, no deduzcas la capacidad a partir de la extensión cargada en ese momento. Pregunta al controlador del reinicio qué versión omitió y activa la cobertura solo en el proceso hijo que la necesite.
- Aplica los ajustes del límite de memoria solo a la configuración temporal del proceso hijo, después del análisis estático, y haz que el ajuste sea el mejor esfuerzo posible con protecciones explícitas.
- Mide las optimizaciones que cargan mucho los procesos antes de conservarlas. Vuelve a validar soluciones antiguas de rendimiento cuando cambien las versiones del entorno de ejecución o de la cadena de herramientas.
## Protege el archivo de bloqueo y fusiona solo pull requests con la CI aprobada
Nunca omitas un lockfile congelado durante una instalación desatendida. Si la resolución de dependencias exige modificarlo, detente y obtén una autorización explícita. Las versiones exactas, los hashes de integridad y la compatibilidad de licencias son límites de la cadena de suministro.
Nunca hagas push directamente a una rama predeterminada protegida, eludas la protección de la rama ni fuerces una fusión administrativa. Utiliza esta secuencia:
1. Crea una rama de función con alcance definido.
2. Realiza el cambio coherente más pequeño y ejecuta comprobaciones específicas.
3. Haz commit según la convención de mensajes exigida por el repositorio.
4. Haz push de la rama y abre una pull request.
5. Espera a que se superen todas las comprobaciones obligatorias de formato, tipos, unidad, integración y extremo a extremo.
6. Corrige los fallos en lugar de eludirlos.
7. Fusiona mediante el método aprobado y retira la rama.
No mezcles refactorización con cambios de comportamiento. Los defectos corregidos exigen pruebas de regresión, las rupturas de compatibilidad exigen notas de publicación e instrucciones de migración explícitas, y el comportamiento visible para usuarios exige documentación de usuario sincronizada.
Deja que la automatización de publicación derive metadatos de los commits convencionales. Utiliza las sustituciones documentadas solo para una reclasificación deliberada y nunca modifiques manualmente los artefactos de publicación generados.
Ejecuta la CI de contribuciones no fiables sin secretos y con permisos de solo lectura. Las vistas previas que contengan secretos deben omitir los forks, salvo que un responsable autorizado las active explícitamente mediante un comando sujeto a verificación de identidad.
Registra cada ejemplo desplegado en la matriz de compilación y añade una prueba de humo que verifique su ruta, estado y contenido esperados. La publicación o el despliegue solo se completa cuando se superan las comprobaciones obligatorias y las evidencias posteriores al despliegue.
