Paso 6: Test-first por defecto

Por: Artiko
oddtest-firsttddpruebasregresion

Paso 6: Test-first por defecto

Objetivos

  • Determinar cuándo aplica la política test-first y qué hacer cuando no.
  • Aplicar el ciclo con la cantidad exacta de pruebas que indica la regla.
  • Realizar una comprobación diferencial.
  • Mantener el estado temporal fuera del cambio.

Una política, sin interruptor

Desde v4.0.0 no existe una opción de TDD estricto: la guía test-first se instala por defecto. gentle-ai sync rechaza el antiguo flag --strict-tdd.

Nota sobre la documentación. docs/agents.md todavía describe Strict TDD como un modo que se configura de forma independiente. Tanto las notas de v4.0.0 como docs/usage.md y el código de sync indican que se retiró. Este curso sigue a estos últimos.


Cuándo aplica

Test-first aplica cuando existen dos cosas:

  1. Una prueba relevante, ejecutable y determinista.
  2. Un resultado esperado claro.

Que haya pruebas o un framework en el proyecto no basta para establecer que aplica. Cuando no aplica, por ejemplo en documentación pasiva, sin ejecutor disponible o sin un RED significativo, se explica la excepción y se hacen comprobaciones funcionales o estructurales proporcionales. La excepción nunca exime de comprobar.

flowchart TD
    A["Cambio de comportamiento"] --> B{"¿Hay prueba relevante, ejecutable<br/>y determinista, y resultado claro?"}
    B -->|"Sí"| C["RED observado"]
    C --> D["GREEN mínimo"]
    D --> E["PRESERVE"]
    E --> F["REFACTOR con pruebas en verde"]
    F --> G["Comprobación diferencial"]
    B -->|"No"| H["Explicar la excepción"]
    H --> I["Comprobaciones funcionales proporcionales"]

El ciclo

FaseQué se haceEvidencia
REDUna prueba por cada regla pedida, que debe fallar por el motivo previstoLa falla observada
GREENEl cambio mínimo que la hace pasarLa prueba enfocada pasando
PRESERVEUna prueba por cada comando u opción existente que el cambio toca, que confirma su comportamiento previoPasa desde el principio, por eso no requiere RED
REFACTORMejorar la claridad mientras las pruebas siguen en verdeLas pruebas enfocadas siguen pasando

Cuántas pruebas

La regla fija un número, y no es “las máximas posibles”:

Write one RED test per requested rule. For every existing command or option the change touches, add one test proving its previous behavior still holds; add no other cases.

internal/components/agentguidance/routing.go

Es decir:

  • Una prueba RED por regla pedida.
  • Una prueba de preservación por cada comando u opción existente afectada.
  • Ninguna otra. El README describe esto como no rellenar con casos adicionales.

Un comportamiento existente cuenta como afectado cuando comparte el código que cambiaste: opciones, parsers, helpers o validación.

Qué tiene que afirmar cada prueba

Una sola prueba por regla no significa una prueba débil. Cada una debe:

  • Afirmar todos los efectos observables de la regla: salida, código de salida y datos persistidos. Las versiones de Pi y OpenCode detallan stdout y stderr exactos, y que la entrada rechazada deje intactos datos y contadores.
  • Cubrir los casos que la propia regla nombra: sus ejemplos, límites y errores.
  • Pasar por la interfaz pública, sin mirar el almacenamiento interno.

Ejemplo

Pedido: “report --export csv debe rechazar --limit 0 con el mensaje ‘limit must be positive’.”

# Prueba RED, una por la regla
$ report --export csv --limit 0
# Se espera: código de salida 1, stderr exacto, ningún archivo creado

# Prueba PRESERVE, una por cada opción compartida que se tocó
$ report --limit 10
# Se espera: la misma salida que antes del cambio

La comprobación diferencial

Es la regla menos conocida y la que detecta regresiones sutiles. Antes de terminar:

  1. Para cada comando existente que comparte el código cambiado,
  2. ejecútalo con la entrada nueva o cambiada, por ejemplo con la opción nueva pasada a un subcomando hermano,
  3. contra el código anterior y contra tu cambio,
  4. y compara stdout, stderr y código de salida.

Cualquier diferencia que nadie pidió es una regresión: se arregla y se fija con una prueba.

sequenceDiagram
    participant A as Copia de la base
    participant B as Tu cambio
    participant C as Comparación
    A->>C: stdout, stderr y código de salida
    B->>C: stdout, stderr y código de salida
    C->>C: ¿Hay alguna diferencia que nadie pidió?
    C-->>B: Sí, es una regresión: arreglar y fijar con prueba

Dónde vive la copia base

El texto canónico pide una copia del commit base en un directorio creado con mktemp -d. Esa copia no se incluye en las pruebas confirmadas: las pruebas que se commitean nunca leen el historial de Git ni un commit fijo.

Nota sobre la documentación. docs/usage.md menciona git stash o una copia de HEAD. El texto instalado en los agentes especifica la copia en mktemp -d, y es la forma que no toca tu árbol de trabajo.


Estado compartido y documentación

Dos reglas acompañan al ciclo:

Estado compartido. Un registro, entrada de lista, archivo o configuración que otros comandos también crean o leen se modifica con la función existente, conservando sus invariantes de orden, unicidad, validación y normalización. Nunca se reimplementa ese paso con otra forma.

Documentación. Si agregas o cambias un comando, una opción o un mensaje, actualizas el texto de ayuda y la documentación que lo describen.


Estado temporal

El cambio no debe arrastrar cachés ni rutas temporales:

  • El estado de pruebas, como directorios temporales, HOME, TMPDIR y cachés de herramientas, queda fuera del árbol de trabajo en un directorio creado con mktemp -d.
  • Si tiene que vivir dentro del árbol, se usa una ruta excluida por Git y se elimina antes de terminar.
  • Los subagentes no borran esos directorios: informan sus rutas exactas, y el parent los elimina después.

Reenviar la política

La política no llega sola a un subagente. El ejecutor se registra en el documento de feature, y tanto el ejecutor como la disciplina de pruebas y la evidencia o excepción se reenvían a cada worker.

Hay dos prohibiciones explícitas: nunca inventar evidencia RED/GREEN y nunca inventar un ejecutor. Si falta un comando exacto, el worker informa la limitación.


La regla que atrapó nueve premisas erróneas

La crónica de RDD cuenta una regla de disciplina relacionada: nunca se edita una prueba existente que falla, se detiene el trabajo y se informa. Según el mantenedor, esa regla detectó nueve premisas equivocadas: nueve veces un agente iba a arreglar algo, una prueba antigua se puso en rojo, y resultó que la prueba tenía razón y el diagnóstico no.

Es una anécdota de un proyecto, no una métrica general, pero ilustra por qué una prueba roja se trata como información.


Actividad

Elige una función de tu proyecto que comparta un helper con otras. Escribe:

  1. La regla nueva y su única prueba RED, con todos sus efectos observables.
  2. La lista de comandos u opciones que comparten el código, con una prueba PRESERVE para cada uno.
  3. Los comandos exactos de tu comprobación diferencial, usando una copia en mktemp -d.

Autoevaluación

  1. Un proyecto tiene pruebas, pero el cambio es documentación pasiva. ¿Qué corresponde?

    • A. Explicar la excepción y hacer comprobaciones estructurales
    • B. Escribir una prueba RED igualmente
    • C. Omitir toda comprobación
    • D. Activar el modo estricto
  2. ¿Cuántas pruebas pide la regla para dos reglas nuevas que afectan a tres opciones existentes?

    • A. Tantas como se pueda
    • B. Dos
    • C. Tres
    • D. Dos RED y tres de preservación, y ninguna más
  3. ¿Qué compara la comprobación diferencial?

    • A. Solo los tiempos de ejecución
    • B. El tamaño de los binarios
    • C. Stdout, stderr y código de salida entre código anterior y cambio
    • D. La cobertura de pruebas
  4. Durante una tarea, una prueba existente se pone en rojo. ¿Qué indica la experiencia que relata el mantenedor?

    • A. Actualizarla para reflejar el nuevo comportamiento
    • B. No editarla: detener el trabajo e informar
    • C. Eliminarla si es antigua
    • D. Marcarla como omitida hasta el cierre
Respuestas
  1. A. La presencia de pruebas no establece que la política sea aplicable.
  2. D. Es el conteo exacto de la regla.
  3. C. Cualquier diferencia no pedida es una regresión.
  4. B. La fuente describe esa regla al relatar la segunda corrida.

Lista de control

  • Compruebo si test-first aplica antes de iniciar el ciclo.
  • Escribo una prueba por regla, con todos sus efectos observables.
  • Identifico lo que comparte el código cambiado y agrego pruebas PRESERVE.
  • Hago la comprobación diferencial en una copia temporal.
  • Nunca informo una ejecución que no observé.

Fuentes

internal/components/agentguidance/routing.go, internal/assets/opencode/agents/gentle-ai-worker.md, docs/usage.md, README.md, internal/cli/sync.go, docs/architecture/the-organic-rdd-story.md, notas de v4.0.0.