SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-09-01

Old Coder: revisa la evidencia, no el código

Aprueba una SPEC y repite el informe EVIDENCE con comandos exactos. Descubre qué aporta mutation testing frente a coverage en el gauntlet de Old Coder.

Qué cambia realmente la skill Old Coder

La skill Old Coder sustituye la revisión de código por la revisión de documentos. El agente de programación escribe una SPEC antes de escribir código, usted aprueba ese documento y sólo entonces lo implementa. Después ejecuta su propio trabajo mediante una pila fija de comprobaciones automatizadas llamada gauntlet y le entrega un informe EVIDENCE con los comandos exactos y los valores reales. Usted lee dos documentos. Nunca lee el diff.

Este intercambio sólo funciona si los dos documentos transmiten la confianza que antes transmitía el diff. La SPEC la transmite porque usted la aprobó antes de que existiera código alguno, por lo que no podía estar adaptada al código que el agente ya hubiera escrito. El informe EVIDENCE la transmite porque cada valor procede de un comando que usted puede ejecutar por su cuenta y comprobar que produce el mismo resultado. Si una de las dos partes pierde rigor, habrá sustituido la revisión por un resumen de la revisión. Eso es peor que leer el diff porque da la sensación de que el trabajo ya está terminado.

La skill está escrita en markdown, por lo que funciona con cualquier agente que siga instrucciones escritas: Claude Code, Codex CLI, Cursor o su propio bucle de trabajo. Pertenece a la misma familia que la skill de personalidad Ponytail lazy senior developer. Si este formato de archivo es nuevo para usted, qué es una skill de agente y cómo carga una explica los aspectos prácticos.

El SPEC es la única decisión que todavía debe tomar

El SPEC es un plan de pruebas escrito antes de que exista el código. El archivo de habilidades exige que incluya cuatro elementos.

  • Escenarios concretos: entradas, salidas esperadas, casos límite y casos de error. divide(1, 0) raises ZeroDivisionError with message X, no «gestiona entradas incorrectas».
  • Restricciones negativas: lo que no debe cambiar, como las pruebas existentes y las firmas de la API pública.
  • Un plan de preparación: cada herramienta y cada dependencia nueva, con una línea que explique por qué se incluye.
  • Una ruta de archivo absoluta para poder abrir el archivo sin tener que buscarlo.

El plan de preparación es donde se nota la fecha de corte del entrenamiento del modelo, porque una herramienta o una versión fijada que recuerde de memoria puede tener un año de antigüedad. Por eso conviene proporcionar al agente una instancia de SearXNG autoalojada para buscar en la web y hacer que compruebe las versiones actuales antes de proponerlas.

Apruébelo y, después, haga el commit. Una especificación que puede editarse después de aprobarla no es un contrato. El commit permite comprobar más adelante que las evidencias se midieron con respecto a aquello que usted firmó.

Esta es la única decisión de sí o no que queda por tomar. Ese es el objetivo y también el riesgo. Trátela como un cambio en producción, porque eso es. Si ya ejecuta una puerta de aprobación explícita delante de las acciones del agente, la aprobación de la especificación encaja en el mismo punto del flujo de trabajo.

El informe EVIDENCE: números acompañados de comandos

El informe EVIDENCE es lo que se lee al final. La competencia exige asignar cada comportamiento especificado a la prueba que lo verifica, informar de cada capa de la batería con el comando ejecutado y su resultado real, obtener cada número de una ejecución nueva después de la última modificación del código y enumerar cada capa omitida junto con el motivo. Los adjetivos no son evidencia. «Las 41 pruebas pasan y la cobertura es de 49/49 sentencias» es un resultado. «Está bien probado» no lo es.

El informe de demostración del repositorio, demo-rate-limiter/evidence.md, identifica su estado de origen mediante un commit y un hash de árbol sha256. Esa línea es más importante de lo que parece, porque indica qué bytes exactos produjeron esos números. Sin ella, un informe puede describir silenciosamente un árbol de trabajo que ya no existe.

Tres reglas contra la manipulación mantienen la honestidad del informe, y el archivo de competencias las establece como absolutas. Nunca debilite una prueba para que pase: no amplíe las aserciones ni aumente las tolerancias. Nunca edite una prueba y la implementación en el mismo paso para obtener el estado correcto, porque una edición simultánea oculta cuál de las dos era incorrecta. Nunca informe de una capa que no se haya ejecutado: «omitida, no hay ninguna herramienta disponible, se usó una mutación manual» conserva la confianza, mientras que inventar un resultado destruye todo el sistema.

Instale la skill y fije el commit instalado

El repositorio es AmazingAng/old-coder y usa la licencia MIT. Su README ofrece una instalación de una sola línea mediante la CLI de skills:

npx skills add https://github.com/amazingang/old-coder

Esto instala lo que contenga main en el momento de ejecutarlo, y la propia CLI puede cambiar. Compruebe dónde se han instalado los archivos antes de asumir que la skill está activa:

ls ~/.claude/skills/old-coder/

Debería ver SKILL.md y un directorio references/. Si no aparece nada, la skill no está en la ubicación que Claude Code busca. Las versiones antiguas de la CLI de skills escribían en ~/.agents/skills/ sin enlazar el resultado con ~/.claude/skills/. Por tanto, los archivos existían en el disco, pero el agente nunca los cargaba. La ejecución de npx skills@latest add ... evita el problema de una CLI obsoleta.

Prefiera el procedimiento manual porque permite registrar qué ha instalado:

git clone https://github.com/AmazingAng/old-coder.git
cd old-coder
git checkout acc5a89
git rev-parse HEAD
mkdir -p ~/.claude/skills
cp -r skills/old-coder ~/.claude/skills/

acc5a89 era la punta de main el 17 August 2026. Elija su propio commit y anótelo. El repositorio se encuentra en desarrollo activo, y la referencia del gauntlet, las plantillas y el protocolo del verificador ya han cambiado de archivo. Si los informes de EVIDENCE no indican qué versión de la skill los evaluó, no podrá distinguir un cambio en su código de un cambio en las reglas. Guarde el hash del commit junto al SPEC, en el mismo repositorio que el código que rige.

Para un agente que no lea ~/.claude/skills, añada skills/old-coder/SKILL.md y skills/old-coder/references/gauntlet.md a su system prompt o a su archivo de reglas. Esa es toda la integración.

Qué se ejecuta dentro del gauntlet

El gauntlet es una pila de capas que se ejecuta una vez que todas las especificaciones tienen un comportamiento correcto. Los nombres de las capas son estos:

  • La suite completa de pruebas, para detectar regresiones. No debe haber fallos nuevos. Los fallos preexistentes deben registrarse primero como línea base.
  • Los tipos estáticos, además de lint y formato, para detectar clases completas de errores y desviaciones.
  • La cobertura de las líneas modificadas, que debe salir con un código distinto de cero cuando no se alcanza el umbral.
  • Las pruebas de mutación, para detectar pruebas que no comprueban nada.
  • Las pruebas basadas en propiedades, para los casos límite que nadie imaginó.
  • Un presupuesto de complejidad, una ejecución real del programa, un análisis de la cadena de suministro y de secretos, y una ejecución de la salud de la suite en orden aleatorio.
  • Capas específicas del dominio, elegidas según el riesgo de la tarea: pruebas de estrés de concurrencia, compatibilidad de API, simulación de rollback y benchmarks de latencia.

La demostración conecta estas capas en un solo script, demo-rate-limiter/tools/gauntlet.sh, usando el toolchain fijado en requirements-dev.txt: pytest, pytest-cov, coverage, hypothesis, mypy, ruff, pip-audit y pytest-randomly, cada uno fijado a una versión exacta (pytest 9.1.1, ruff 0.16.0, a fecha de agosto de 2026). Ejecútelo:

cd demo-rate-limiter
python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt -e .
./tools/gauntlet.sh

El script muestra un banner por cada capa, como === tests + coverage === y === mutation ===, y termina con === gauntlet: all layers green ===. Se ejecuta con set -e, por lo que la primera capa que falla detiene el script y ese banner final no se muestra. Ver el banner final es la comprobación: significa que todas las capas anteriores terminaron con código cero.

Hay un detalle de ese script que conviene copiar en el suyo. La capa de cobertura está escrita así:

pytest -q --cov=ratelimiter --cov-report=term-missing --cov-fail-under=100

Sin --cov-fail-under, pytest --cov muestra un porcentaje y termina con código 0, independientemente de cuánto haya disminuido la cobertura. Esa es una capa que permite fallos dentro de un script cuya primera línea promete detenerse ante el primer fallo. Una capa del gauntlet que no puede fallar es sólo decoración.

Qué aporta el testing de mutaciones frente a la cobertura

La cobertura responde a una pregunta: ¿la suite ejecutó esta línea? No puede responder a la pregunta que realmente importa: si alguna aserción habría fallado si la línea fuera incorrecta. Un test que llama a una función y no comprueba nada sigue mostrando cobertura completa en todas las líneas que toca. La cobertura detecta código no probado. No detecta tests que no comprueban nada.

El testing de mutaciones responde directamente a la segunda pregunta. Cambia el código de forma intencionada, una pequeña modificación cada vez, y vuelve a ejecutar la suite. Si la suite falla, el mutante muere, lo que significa que alguna aserción estaba comprobando ese comportamiento. Si la suite sigue pasando, el mutante sobrevive: la línea se ejecutó y nadie comprobó el resultado.

La demostración hace esto con tools/mutants.py. Inserta modificaciones individuales numeradas en src/ratelimiter/__init__.py, ejecuta pytest después de cada una y luego restaura el archivo. Son los errores que comete una persona cansada: >= se convierte en > o se elimina un valor de retorno.

La regla para matar mutantes de ese ejecutor es la parte que más suelen implementar mal los scripts de mutaciones caseros. Sólo el código de salida 1 de pytest cuenta como un mutante muerto, porque 1 significa que los tests se ejecutaron y al menos uno falló. El código de salida 0 significa que el mutante sobrevivió. Cualquier otro resultado, como un error de recopilación o que no se hayan recopilado tests, significa que no se verificó nada y no debe contabilizarse. Un script que trata cualquier código distinto de cero como una muerte cuenta sus propios fallos como éxitos, por lo que esa cifra sólo puede aumentar.

En el mismo archivo hay otros dos detalles importantes. El mutante M11 se excluye de la lista porque es equivalente: podar una entrada caducada en lugar de todas las entradas caducadas produce el mismo comportamiento observable con un reloj monótono, por lo que ningún test puede matarlo. Además, el ejecutor establece PYTHONDONTWRITEBYTECODE=1 mientras que el proceso de pruebas elimina primero todos los __pycache__, porque dos mutantes del mismo tamaño escritos en el mismo segundo pueden compartir un .pyc almacenado en caché y, en ese caso, el segundo hereda el veredicto del primero.

Ese riesgo explica por qué el proceso de pruebas ejecuta un control negativo antes de la pasada de mutaciones real:

.venv/bin/python tools/mutants.py --negative-control
.venv/bin/python tools/mutants.py

El control ejecuta dos mutantes con una hora de modificación fijada: uno que debe morir y otro que es estrictamente equivalente y debe sobrevivir. Si ambos aparecen como muertos, la caché de bytecode se reutilizó entre ejecuciones y todas las cifras de mutantes muertos del informe están infladas. Esto concreta la regla de esta habilidad sobre los verificadores. pytest y mypy han demostrado durante muchos años cómo deben comportarse cuando fallan. Un script que escribiste la semana pasada aún no lo ha demostrado, así que comprueba que puede fallar antes de confiar en él cuando pasa, y registra esa prueba en EVIDENCE.

ChartMutants killed by each suite run alone (demo-rate-limiter evidence.md, August 2026)
The data behind this chart
[
  {
    "label": "Scenario tests",
    "mutants_killed": 22,
    "mutants_run": 22
  },
  {
    "label": "Property tests",
    "mutants_killed": 3,
    "mutants_run": 22
  }
]

El propio informe EVIDENCE de la demostración muestra por qué una única cifra agregada sigue ocultando información. La suite de escenarios mató 22 de 22 mutantes. Los tests basados en propiedades, ejecutados de nuevo por separado contra los mismos mutantes, mataron 3. La muerte se atribuye al test que falla primero, por lo que un total perfecto valida la suite en conjunto, pero no dice nada sobre ninguna capa concreta. Esas propiedades siguen siendo útiles porque detectan formas de entrada que nadie enumeró. No soportan por sí solas la corrección del sistema; sólo se descubre midiendo cada capa por separado.

Ejecute todas las comprobaciones en un servidor, no en su portátil

Un informe EVIDENCE afirma que determinados comandos produjeron determinados valores. La afirmación sólo se puede comprobar si otra persona puede obtener los mismos valores, y un portátil es el peor lugar para intentarlo. Su versión de Python es una revisión diferente, y su PATH incluye herramientas que no estarán disponibles en la siguiente máquina. Las pruebas de mutación lo complican aún más, porque vuelven a ejecutar toda la suite una vez por mutante. Por tanto, la lista del ejemplo supone 22 ejecuciones adicionales de la suite.

Colóquelo en un contenedor dentro de un VPS. El contenedor fija el sistema operativo y el intérprete, el requirements-dev.txt fijado garantiza las herramientas y el VPS proporciona una máquina que no está ejecutando también su navegador.

FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends \
      python3 python3-venv git ca-certificates \
 && rm -rf /var/lib/apt/lists/*
WORKDIR /work
docker build -t gauntlet:24.04 .
docker run --rm -v "$PWD:/work" -w /work/demo-rate-limiter gauntlet:24.04 \
  sh -c 'python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt -e . && ./tools/gauntlet.sh'

Una ejecución correcta termina en === gauntlet: all layers green ===. Dos pasos necesitan acceso a la red saliente: la instalación mediante pip de las herramientas fijadas y la capa pip-audit, que comprueba las dependencias frente a un servicio de vulnerabilidades. Una ejecución sin conexión no omite esa capa de forma silenciosa. Falla, que es el comportamiento que se espera de una puerta de control.

Para ejecutar la comprobación en cada push, el mismo script se convierte en un paso de un trabajo de CI. El repositorio ejecuta su propia batería de comprobaciones en GitHub Actions sobre ubuntu-latest con Python 3.12. Configure runs-on para usar un runner autohospedado y el trabajo se ejecutará en su VPS:

name: gauntlet
on:
  push:
    branches: [main]
jobs:
  gauntlet:
    runs-on: self-hosted
    defaults:
      run:
        working-directory: demo-rate-limiter
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: python -m venv .venv && .venv/bin/pip install -r requirements-dev.txt -e .
      - run: ./tools/gauntlet.sh

Mantenga el desencadenador limitado a los pushes de las ramas que controla. Un runner autohospedado que también compile pull requests de forks ejecuta código de terceros en su servidor con las credenciales de su runner. El mismo razonamiento se aplica al propio agente: asígnele una VM desechable que pueda eliminar en lugar de su estación de trabajo. Si quiere que el resultado de la batería llegue al lugar donde se debate el cambio, intégralo con un agente autohospedado de revisión de PR.

Dónde falla este enfoque

El primer fallo es estructural y ninguna herramienta puede eliminarlo. El gauntlet convierte las restricciones de tu SPEC en evidencia ejecutable. No puede decirte si la SPEC era correcta. Si apruebas una SPEC que codifica un requisito incorrecto, obtienes un informe EVIDENCE impecable sobre el programa equivocado: cobertura completa, todos los mutantes eliminados, todas las capas en verde y un software que hace algo que no querías. Cada hora que ahorres al no leer el diff debería dedicarse a leer la SPEC.

El segundo problema son los checkers. El repositorio lo reconoce en su propio archivo de evidencia. Su protocolo de verificación independiente ejecutó seis rondas; la sexta devolvió failed, y las correcciones realizadas después de esa ronda nunca se volvieron a verificar. Por tanto, el estado que se distribuye no se verificó de extremo a extremo. Una capa de lint del shell figura como no disponible, no como superada. Las rondas anteriores encontraron defectos de comportamiento reales y un mutation runner defectuoso oculto tras estados que ya habían informado de un resultado correcto. Un gauntlet en verde no se autentica por sí mismo.

El tercer problema es el alcance. Una lista de mutantes escrita manualmente sólo cubre los errores que alguien pensó en introducir, y cada mutante equivalente eliminado de esa lista representa una decisión en la que estás confiando. Las herramientas de mutation testing disponibles como paquetes (mutmut, cosmic-ray, Stryker, PIT) generan mutantes de forma sistemática y son la opción predeterminada más adecuada cuando existe una para tu lenguaje.

Calibre el esfuerzo según el riesgo

La habilidad define tres niveles y exige que el agente declare cuál ha elegido.

  • Nivel 1, trivial: un error tipográfico, un comentario o un valor de configuración. Ejecute la suite completa y el linter, sin añadir pruebas, e indique en una frase por qué no eran necesarias.
  • Nivel 2, normal: una corrección de errores o una funcionalidad pequeña. Ejecute el ciclo completo. Una corrección de errores debe comenzar con una prueba fallida que reproduzca el error, para que el error de ayer se convierta en una prueba de regresión mañana.
  • Nivel 3, crítico: dinero, autenticación, pérdida de datos, concurrencia o una API pública. Comience con un modelo de fallos que enumere las formas en que este cambio puede causar daños. Añada una capa de pruebas rigurosas para cada caso. Después, ejecute el ciclo completo junto con pruebas de propiedades, pruebas de mutación y una pasada explícita que intente atacar la implementación con entradas maliciosas.

El nivel 3 también incluye un paso experimental. Un segundo agente, con un contexto nuevo, sólo ve el contrato de la tarea, la SPEC aprobada y el estado del código fuente. Intenta romper el trabajo terminado antes de firmar EVIDENCE. No corrige nada. Informa de sus hallazgos y una persona evalúa lo que ha encontrado. Esto reduce la correlación causada por compartir el contexto de la tarea. No reduce la correlación causada por compartir el mismo modelo.

Si prefiere crear algo con esta estructura en lugar de adoptar esta habilidad, la guía para escribir su propia habilidad de agente describe la disposición de archivos y el campo de descripción que determina cuándo carga el agente.

FAQ

¿Qué detectan las pruebas de mutación que la cobertura de código no detecta?

La cobertura registra que se ejecutó una línea. No puede registrar si alguna aserción habría fallado si esa línea fuera incorrecta. Por eso, una prueba que llama a una función y no comprueba nada sigue mostrando una cobertura completa. Las pruebas de mutación modifican el código deliberadamente, una edición cada vez, y vuelven a ejecutar la suite. Un mutante superviviente significa que la línea se ejecutó y que nada verificó el resultado. Por eso la habilidad incluye «nunca persigas los valores de cobertura» como regla absoluta y señala la mutación como la capa que detecta la manipulación de las métricas.

¿Tengo que seguir leyendo el código que escribe mi agente?

Con este flujo de trabajo, lees la SPEC antes de programar y el informe EVIDENCE después. También compruebas el informe ejecutando de nuevo los comandos que cita. El diff pasa a ser opcional. El problema es que todo tu criterio se concentra ahora en un solo documento. Una especificación con un requisito incorrecto produce un gauntlet en verde para un programa que no querías. Dedica a la especificación el tiempo que has ahorrado.

¿Puedo ejecutar el gauntlet de Old Coder en CI en mi propio servidor?

Sí. Ese es el lugar más adecuado. Instala la toolchain fijada desde requirements-dev.txt dentro de un contenedor y ejecuta el script del gauntlet del proyecto como un paso del job. En GitHub Actions, configura runs-on: self-hosted y registra un runner en tu VPS. Mantén el activador limitado a los pushes en ramas que controles. Un runner autoalojado que compile pull requests de forks ejecuta código no confiable con las credenciales de tu runner.

¿Qué versión de la habilidad debo instalar?

Fija una versión. El repositorio está en desarrollo activo y sus archivos de referencia ya se han separado y movido. Por tanto, un informe generado el mes pasado puede haberse evaluado con reglas diferentes. Clona el repositorio, cambia a un commit específico, copia skills/old-coder en ~/.claude/skills/ y registra ese hash del commit junto a tu SPEC. Así, un cambio en la evidencia implica un cambio en tu código.