Tag: Spec Driven Development

  • Refactorizar código legacy con IA: el método SDD en brownfield

    Refactorizar código legacy con IA: el método SDD en brownfield

    El fichero se llamaba pricing.ts, tenía 1.100 líneas y un comentario en la línea 3 que decía // NO TOCAR — hablar con Javi antes. Javi se había ido de la empresa en 2021.

    Cero tests. Cero documentación. Y toda la facturación pasando por ahí.

    Hice lo que hace todo el mundo la primera vez que intenta refactorizar código legacy con IA: se lo pegué entero a Claude Code y le pedí que lo dejara limpio. Me devolvió algo precioso. Funciones puras, nombres decentes, 300 líneas en vez de 1.100.

    Y roto para los pedidos que acumulaban cupón y descuento de socio a la vez.

    El agente no alucinó nada. Hizo exactamente lo que le pedí. Le pedí arreglar un código cuya intención nadie le había explicado, porque nadie la sabía.

    Esa es la tesis de este post: en legacy la spec no describe la feature que quieres, describe el comportamiento que ya tienes. Y por eso el primer artefacto no es spec.md, son los tests de caracterización.

    Por qué refactorizar código legacy con IA falla sin tests

    Refactorizar código legacy con IA usando SDD consiste en invertir el ciclo habitual: primero tests de caracterización que congelan el comportamiento observable, después una spec que documenta lo que el sistema ya hace, y solo entonces plan y tasks.

    El motivo es simple. Un modelo lee código y ve perfectamente qué hace. Lo que no puede ver es qué debería hacer.

    En un proyecto nuevo eso da igual, porque la intención está en tu cabeza y la escribes tú. Es lo que hacemos cuando arrancamos un greenfield con slices verticales: la spec va delante porque describe algo que todavía no existe.

    En legacy la intención está enterrada bajo seis años de parches de viernes por la tarde. Y ahí aparece el problema real: ningún modelo distingue una regla de negocio rara de un bug que lleva años tolerándose.

    En mi pricing.ts había un Math.floor donde cualquiera pondría Math.round. Claude lo "arregló". Llevaba ahí desde 2019 porque el departamento financiero quería redondear siempre a favor del cliente.

    Eso no es un bug. Es un requisito no escrito. Y el agente no tenía forma humana de saberlo.

    Los antipatrones de este escenario los desarrollé en los 5 errores fatales al refactorizar legacy con IA, así que no los repito. El método positivo empieza invirtiendo el orden.

    Spec greenfield Spec brownfield
    Qué describe Lo que quieres construir Lo que ya hace el sistema
    Fuente de verdad Tu criterio de producto El código en producción
    Primer artefacto spec.md Tests de caracterización
    Criterio de éxito Cumple los casos de uso nuevos No cambia ninguna salida observable
    Ambigüedad Se resuelve preguntando Se resuelve ejecutando
    Riesgo principal Construir lo que no toca Romper lo que ya funcionaba

    En greenfield el ciclo es spec → plan → tasks → código. En brownfield es tests → spec → plan → tasks → código. La spec sigue existiendo, pero llega en segundo lugar: hasta que no ejecutas el módulo no sabes qué escribir en ella.

    Paso 0 — Acota el blast radius antes de abrir el editor

    La regla que más refactors me ha salvado: si no puedes escribir en una línea qué NO vas a tocar, no empieces.

    Escribe estas cuatro cosas antes de nada:

    • Dentro: src/pricing.ts y sus dos helpers.
    • Fuera: el modelo de datos, los endpoints, la UI de checkout.
    • Consumidores: quién importa esto. Lanza un rg sobre el repo y pega la lista tal cual.
    • Contrato público: las funciones exportadas que otros usan. Esas firmas no se tocan.

    Ese último punto es el que hace el trabajo acotable: si la frontera del módulo se mueve, ya no es un refactor, es un rediseño.

    Paso 1 — Arqueología asistida: el agente lee, no escribe

    Aquí Claude Code es brutalmente bueno, y es la parte que casi nadie usa. El agente tiene prohibido cambiar una sola línea.

    El prompt que uso, más o menos literal:

    Lee src/pricing.ts. No propongas mejoras ni refactorices nada.
    
    Produce docs/legacy/pricing-observado.md con:
    1. Cada rama de decisión del módulo, con la condición exacta que la activa.
    2. Las entradas: tipos reales, no los declarados. Marca los que en la práctica
       llegan como null o undefined.
    3. Las salidas: forma del retorno en cada rama.
    4. Efectos secundarios: I/O, escrituras, logs, mutación de argumentos, lecturas
       de Date/Math.random o de variables globales.
    5. Una sección "Comportamientos sospechosos": cosas que parecen bugs.
       NO las arregles. Solo lístalas con número de línea.
    6. Una sección "Preguntas que no puedo responder leyendo el código".
    

    Las secciones 5 y 6 son el oro: una lista lo que el agente habría "arreglado" solo, la otra lo que tienes que ir a preguntarle a un humano o a los logs de producción.

    En pricing.ts la sección 6 tenía nueve preguntas. Siete las resolví mirando datos reales. Dos las resolvió el responsable de facturación en cinco minutos. Ese día no escribí código y fue el día más productivo del refactor.

    Paso 2 — Tests de caracterización: congela el comportamiento, incluso el feo

    Un test de caracterización no comprueba que el código sea correcto. Comprueba que sigue haciendo lo mismo. En TDD el test va delante y define lo deseable; aquí va detrás y define lo existente.

    Aunque lo existente sea horrible.

    // pricing.characterization.test.ts
    import { describe, it, expect } from 'vitest'
    import { calcularPrecioFinal } from '../src/pricing'
    
    // Casos capturados de pedidos reales de producción, anonimizados.
    const CASOS = [
      { nombre: 'base sin descuentos', pedido: { subtotal: 100, cupon: null, pais: 'ES', socio: false } },
      { nombre: 'cupon y socio acumulados', pedido: { subtotal: 100, cupon: 'VIP10', pais: 'ES', socio: true } },
      { nombre: 'cupon caducado', pedido: { subtotal: 100, cupon: 'OLD20', pais: 'ES', socio: false } },
      { nombre: 'pais sin IVA', pedido: { subtotal: 100, cupon: null, pais: 'US', socio: false } },
      { nombre: 'decimales feos', pedido: { subtotal: 1234.56, cupon: 'VIP10', pais: 'ES', socio: true } },
      { nombre: 'subtotal cero', pedido: { subtotal: 0, cupon: 'VIP10', pais: 'ES', socio: true } },
    ] as const
    
    // CONGELADO: el caso 'decimales feos' devuelve un céntimo de menos por el
    // Math.floor de pricing.ts:412. Se arregla DESPUÉS del refactor, en un
    // commit propio. Ver LEG-14.
    describe('calcularPrecioFinal — caracterización', () => {
      it.each(CASOS)('$nombre', ({ pedido }) => {
        expect(calcularPrecioFinal(pedido)).toMatchSnapshot()
      })
    })
    

    Fíjate en lo que no hay: ningún valor esperado escrito a mano. El snapshot lo genera la primera ejecución. Tú no decides la salida correcta, la registras.

    El término viene de Working Effectively with Legacy Code (Michael Feathers, 2004), y en Vitest 5 lo implementas con toMatchSnapshot().

    Después abres el fichero de snapshots y lo lees entero. Ahí aparecen las sorpresas y ahí apuntas los // CONGELADO:. Cada uno es un ticket futuro, no una excusa para tocar nada ahora.

    Y sí, congelas el bug a propósito. Si arreglas comportamiento y estructura en el mismo commit, cuando algo falle en producción no sabrás cuál de las dos cosas lo rompió.

    Paso 3 — La spec brownfield

    Ahora, y solo ahora, escribes la spec. Con los tests en verde delante deja de ser un ejercicio de memoria, y las secciones que importan no son las de un proyecto nuevo:

    # Spec — Refactor de pricing
    
    ## Comportamiento observado
    Documentado en docs/legacy/pricing-observado.md.
    Congelado en pricing.characterization.test.ts (6 casos).
    
    ## Contrato público (NO cambia)
    calcularPrecioFinal(pedido: Pedido): Precio
    - Devuelve `total` en céntimos como number. No se migra a bigint en este refactor.
    - Nunca lanza: ante entrada inválida devuelve { total: 0, error: string }.
    
    ## Efectos secundarios actuales
    - Escribe en la tabla pricing_audit. SE MANTIENE.
    - Lee process.env.TAX_MODE en caliente. SE MANTIENE, se aísla en config.ts.
    - Muta el objeto `pedido` recibido. SE ELIMINA: ningún consumidor depende de
      ello, verificado en los 4 call sites.
    
    ## Deuda congelada a propósito
    - LEG-14: redondeo con Math.floor en la línea 412.
    - LEG-15: cupón caducado devuelve descuento 0 en vez de error.
    
    ## Fuera de alcance
    Modelo de datos, endpoints, UI de checkout, migración a bigint.
    
    ## Criterio de aceptación
    Los 6 tests de caracterización pasan sin modificar sus snapshots.
    El test de equivalencia legacy/refactor pasa en las 72 combinaciones.
    

    Es corta a propósito. Y es lo que le das al agente en cada task, no el fichero de 1.100 líneas.

    El formato completo lo tienes en el libro de Spec-Driven Development. Para el esqueleto uso el skill dominicode-sdd-creator, que genera spec.md + plan.md + tasks.md; el contenido brownfield lo pones tú, porque sale de los tests.

    Si dudas de cuánta ceremonia merece el módulo, el criterio está en los tres niveles de SDD. Un refactor de legacy con dinero de por medio es nivel alto, sin discusión.

    Paso 4 — Plan por fases, tasks pequeñas, un commit verde cada una

    El plan de un refactor brownfield tiene siempre la misma forma:

    1. Aislar. Extraer funciones puras sin cambiar la lógica. Copiar, no reescribir.
    2. Tipar los bordes. Con los tipos reales del paso 1, no los declarados.
    3. Sustituir por partes. La implementación nueva convive con la vieja mientras dure.
    4. Borrar el legacy. Cuando la equivalencia lleve dos semanas en verde.

    La fase 3 es la que necesita andamio. Copia el original a pricing.legacy.ts, deja pricing.ts para la implementación nueva, y este es todo el andamio:

    // pricing.equivalence.test.ts
    import { describe, it, expect } from 'vitest'
    import { calcularPrecioFinal as legacy } from '../src/pricing.legacy'
    import { calcularPrecioFinal as refactor } from '../src/pricing'
    
    const subtotales = [0, 9.99, 100, 1234.56]
    const cupones = [null, 'VIP10', 'OLD20']
    const paises = ['ES', 'US', 'DE']
    const socios = [true, false]
    
    describe('legacy vs refactor — equivalencia', () => {
      for (const subtotal of subtotales) {
        for (const cupon of cupones) {
          for (const pais of paises) {
            for (const socio of socios) {
              const pedido = { subtotal, cupon, pais, socio }
              it(`${subtotal} / ${cupon ?? 'sin cupon'} / ${pais} / socio=${socio}`, () => {
                expect(refactor(pedido)).toEqual(legacy(pedido))
              })
            }
          }
        }
      }
    })
    

    72 combinaciones que el agente ejecuta solo cada vez que cierra una task. Y ojo: si el test sale intermitente no tienes un problema de refactor, tienes un Date.now() o un Math.random() sin inyectar. Arréglalo antes de seguir.

    Regla de tamaño de task: si el diff no lo puedes leer entero en diez minutos, pártela. El límite no lo pone el agente, lo pone tu capacidad de revisar lo que produjo — que es el verdadero cuello de botella de trabajar con agentes.

    Paso 5 — Qué haces cuando un test se pone rojo

    Un test de caracterización en rojo tiene tres causas. Míralas en este orden.

    Uno: el refactor rompió algo. Nueve de cada diez veces, por mi experiencia. Revierte la task, no la parchees: el diff es pequeño precisamente para que revertir sea barato.

    Dos: el refactor arregló un bug sin querer. Pasa más de lo que parece y es una trampa. Revierte igual y arréglalo en su propio commit, con su snapshot actualizado. Un cambio de comportamiento colado dentro de un refactor pasa desapercibido en la review casi siempre.

    Tres: el test no era determinista. Fechas, aleatoriedad, orden de un Object.keys, zona horaria. Eso no es caracterización, es ruido. Arréglalo en el test o inyecta la dependencia.

    La regla que resume el paso 5 entero: un refactor nunca cambia comportamiento, y un cambio de comportamiento nunca se llama refactor. Commits distintos, PRs distintas, riesgos distintos.

    Este bucle es el mismo que aplico en TDD potenciado por IA, solo que en legacy los tests no los escribes para diseñar: los escribes para tener permiso a tocar.

    Cómo empezar a refactorizar legacy con Claude Code el lunes

    Coge el fichero que todo el mundo evita en tu repo. No lo refactorices. Haz solo esto, y no tardas más de una hora.

    Escribe en una línea qué entra y qué queda fuera. Lanza a Claude Code el prompt de arqueología del paso 1 en modo lectura. Y escribe cinco tests de caracterización con los casos que ya te sabes de memoria, porque son los que se rompen cada trimestre.

    El lunes no refactorizas nada. El martes ya puedes, y con red.

    Cuando quieras montar la verificación en serio — el AGENTS.md, los carriles del agente y los criterios que se comprueban solos — está en el ebook gratuito de Revisión por Contrato. Y el ciclo completo de idea a producto con Claude Code ejecutando tasks es el recorrido del curso Construye con IA.

    El código legacy no da miedo por antiguo. Da miedo porque no sabes qué hace. Y eso se arregla escribiendo tests, no reescribiendo código.

    Preguntas frecuentes

    ¿Qué es un test de caracterización y en qué se diferencia de un test unitario normal?

    Un test unitario afirma que el código hace lo correcto. Un test de caracterización afirma que sigue haciendo lo mismo que antes, sea correcto o no. No lo escribes a mano: ejecutas el módulo con entradas reales y registras la salida en un snapshot. Su único trabajo es ponerse rojo cuando el refactor cambia una salida observable.

    ¿Merece la pena congelar un comportamiento que sé que es un bug?

    Sí, siempre. Si arreglas el bug en el mismo commit en el que reestructuras el código y algo revienta en producción, no podrás distinguir cuál de las dos cosas lo rompió. Congélalo con un comentario que explique la sospecha y su ticket, y arréglalo después en un commit propio donde el cambio de snapshot sea la parte visible de la pull request.

    ¿Cuánto código legacy le puedo dar a Claude Code de una vez?

    Menos del que cabe. El límite útil no es la ventana de contexto, es lo que tú puedes verificar después. Yo trabajo módulo a módulo y en cada task le paso la spec brownfield y los tests, no el fichero original. Una vez documentado el comportamiento en el paso 1, ese documento sustituye al código fuente como contexto.

    ¿Puedo saltarme los tests de caracterización si el módulo ya está tipado con TypeScript estricto?

    No. Los tipos garantizan la forma del dato, no el valor. Un refactor que cambia Math.floor por Math.round, que invierte el orden de dos descuentos o que redondea antes en vez de después compila perfecto, pasa el type-check y factura mal. Los tipos protegen el contrato; los tests de caracterización protegen el comportamiento.

    ¿Y si el módulo legacy no se puede ejecutar de forma aislada?

    Entonces esa es tu primera task, y no es refactorizar. Si no puedes invocar la función sin levantar media aplicación, lo que falta es una costura: inyectar la base de datos, el reloj y las llamadas HTTP para poder ejecutarla con entradas controladas. Feathers lo llama seam. Hasta que no consigues ejecutar el módulo con entradas que tú decides, no hay tests de caracterización posibles ni refactor seguro.

    ¿Sirve este método si el módulo legacy no está en TypeScript?

    Sí, el orden no cambia. Lo único que necesitas es un runner con snapshots: pytest con syrupy en Python, ApprovalTests en Java o C#, o el propio Vitest si es JavaScript sin tipar. Lo que sí cambia es el paso de tipar los bordes: sin tipos estáticos pierdes la red del compilador y el peso recae entero sobre los tests de caracterización, así que conviene capturar más casos de los que capturarías en TypeScript.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • SDLC context engineering: arregla el ciclo, no el prompt

    SDLC context engineering: arregla el ciclo, no el prompt

    El mismo agente. El mismo modelo. Prácticamente el mismo prompt.

    En uno de mis repositorios la tarea salió a la primera. En el otro, el agente se inventó un helper que no existía y escribió los tests con una librería que ese proyecto abandonó hace más de un año.

    No falló el modelo. Falló todo lo que había alrededor del modelo.

    Y eso que hay alrededor tiene nombre: SDLC context engineering. Tu ciclo de desarrollo es la fábrica del contexto que consume el agente, y si la fábrica va mal, da igual cómo escribas el prompt.

    El primer repositorio tiene un CLAUDE.md con las convenciones escritas, una carpeta de decisiones de arquitectura y un índice del contenido previo que el agente puede consultar. El segundo tiene un README viejo y el resto vive en mi cabeza.

    Y ahí está el problema: cuando el contexto vive en tu cabeza, el agente tiene que adivinarlo. Adivinar, en un modelo de lenguaje, se llama alucinar.

    Por eso llevo meses insistiendo en lo mismo: el prompt no es la unidad de contexto. Puedes escribir el prompt más elaborado del mundo, con sus tres adjetivos y su frase en mayúsculas, que si la información que necesita el agente no existe en ningún sitio legible, no va a aparecer porque tú se lo pidas con más énfasis.

    El contexto no se escribe en el prompt. Se fabrica antes, en tu ciclo de desarrollo.

    Opero Dominicode solo: cursos, libros, una plataforma y un canal. No tengo un equipo que rellene los huecos por mí, así que los huecos los tengo que cerrar en el proceso. De ahí sale la idea que más ha cambiado mi forma de trabajar en el último año:

    Tu SDLC no es un proceso para humanos. Es la cadena de montaje que fabrica el contexto que consumen tus agentes.


    Qué es el SDLC context engineering

    El SDLC context engineering es tratar tu ciclo de vida del software como el sistema que fabrica el contexto que consumen tus agentes de IA.

    Cada una de las cinco fases —requisitos, diseño, implementación, code review y documentación— deja de producir artefactos para humanos y pasa a producir artefactos que una máquina puede leer, verificar y ejecutar: una spec con límites, un esquema de validación, una suite de tests como gate, un diff acotado y contexto versionado en el repositorio.

    La diferencia con el prompt engineering es de capa. El prompt engineering optimiza la instrucción de un turno. El SDLC context engineering optimiza la información que esa instrucción tiene disponible, y esa información la produce tu proceso, no tú en el momento de escribir.


    Qué cambia cuando el que lee el proceso es una máquina

    Cuando el que lee tu proceso es una máquina cambia el destinatario de cada artefacto: deja de valer lo que un humano completa con conocimiento implícito y solo cuenta lo que cabe en la ventana de contexto.

    El ciclo de vida clásico producía artefactos para personas: un ticket de tres líneas, la foto de una pizarra, un hilo de Slack, una reunión de refinamiento.

    Todo eso funciona con humanos por una razón que casi nunca decimos en voz alta: una persona rellena los huecos con conocimiento implícito. Sabe que en este proyecto los servicios van en esa carpeta. Sabe que ese campo del modelo está deprecado aunque siga ahí. Y, sobre todo, sabe a quién preguntar cuando algo no cuadra.

    Un agente no tiene a quién preguntar. Solo tiene lo que le entre por la ventana de contexto.

    Así que cada fase de tu ciclo tiene dos versiones posibles: la que produce algo para un humano y la que produce algo que una máquina puede leer, verificar y ejecutar.

    # Fase del ciclo Artefacto para humanos Artefacto para agentes
    1 Requisitos Ticket de 3 líneas spec.md con límites explícitos
    2 Diseño Diagrama en una pizarra Contratos ejecutables que validan
    3 Implementación "En mi máquina funciona" Tests como gate de salida
    4 Code review "A mí me parece bien" Diff acotado + auditor automático
    5 Documentación Wiki de hace tres años Contexto versionado en el repositorio

    La columna de la derecha es tu context engineering. No es un documento aparte que escribes el viernes por la tarde: es el residuo natural de un ciclo bien montado.

    Vamos fase por fase.


    1. Requisitos: del ticket de tres líneas al spec.md

    Qué falla: un ticket ambiguo no le da al agente lo único que de verdad necesita. Y no es la descripción de la funcionalidad: son los límites.

    Esta es la frase que más repito y la que más discusión genera: el alcance no es lo que el agente tiene que hacer, es lo que el agente no puede tocar.

    Un agente al que le pides "añade validación al formulario de registro" y no le dices nada más, se expande. Toca el modelo de datos porque le pareció que hacía falta. Refactoriza el componente de al lado porque estaba feo. Añade una dependencia. Y cuando abres el diff, tienes once archivos modificados y ninguna forma rápida de saber cuáles querías.

    Una spec no necesita ser larga. Una página con cuatro bloques:

    • Contratos de datos. La forma exacta de lo que entra y lo que sale.
    • Archivos afectados. Las rutas concretas que se pueden tocar.
    • Fuera de alcance. Lo que no se toca, escrito explícitamente.
    • Criterio de terminado. Qué comando tiene que pasar en verde.

    Con esos cuatro bloques, una spec entera te cabe en la pantalla:

    # Spec — Validación del formulario de registro
    
    ## Contratos
    - Entrada: { email: string, password: string, acceptedTerms: boolean }
    - Salida: { ok: true } | { ok: false, errors: FieldError[] }
    
    ## Archivos afectados
    - src/features/auth/register-form.tsx
    - src/features/auth/register.schema.ts
    
    ## Fuera de alcance
    - No tocar el modelo de usuario ni las migraciones
    - No añadir dependencias nuevas
    - No refactorizar componentes vecinos
    
    ## Terminado cuando
    - `bun test src/features/auth` pasa en verde
    - `tsc --noEmit` sin errores
    

    Ese tercer bloque es el que mejor retorno da de todo el documento, y es el que casi nunca veo escrito.

    Improvisar aquí no sale gratis, y el coste se puede calcular turno a turno: lo hice en la factura del vibe coding. Si tus specs ya existen pero el agente sigue desviándose, el problema suele estar en uno de estos 7 fallos. Y si quieres saber hasta dónde llevar el enfoque, están los tres niveles de Spec-Driven Development.

    La metodología completa, con las plantillas que uso a diario, está en el libro de Spec-Driven Development.


    2. Diseño: del diagrama en la pizarra a contratos ejecutables

    Qué falla: si la forma de tus datos vive dispersa por el código, el agente inventa propiedades. Y las inventa con una seguridad absoluta, porque estadísticamente user.email es un campo muy razonable aunque en tu proyecto se llame user.contactAddress.

    La solución no es documentar los tipos en un wiki. Es que la definición y la verificación sean el mismo artefacto.

    Un esquema de validación —Zod 4 en el ecosistema TypeScript, pero el principio vale para cualquier stack— hace tres cosas a la vez:

    • Describe la forma de los datos en un sitio único y localizable.
    • La comprueba en ejecución, así que si la descripción miente, algo se rompe y te enteras.
    • Genera el tipo con z.infer, así que la definición y la verificación salen del mismo artefacto y se actualizan a la vez.

    Esa segunda parte es la que lo convierte en contexto fiable. Un diagrama puede quedarse obsoleto en silencio durante dos años. Un esquema que se ejecuta, no: cuando un campo obligatorio cambia de tipo o desaparece, revienta y te enteras.

    Con un matiz que conviene saber, porque es donde la gente se confía: por defecto z.object() descarta las claves que no conoce en lugar de fallar. Si la API empieza a devolver campos nuevos, tu esquema los tira sin decir nada. Para que esa deriva también haga ruido necesitas z.strictObject(). El esquema te protege del campo que falta; del campo que sobra, solo si se lo pides.

    Y no confundas una cosa con la otra: los tipos de TypeScript desaparecen al compilar y no validan nada en ejecución. Evitan bugs antes de desplegar, que no es poco, pero el que comprueba lo que entra de verdad por la API es el esquema.

    Estos patrones —esquemas como contrato, inferencia de tipos y validación en los bordes— son los que desarrollo en el curso de Zod para TypeScript.

    La otra mitad del diseño es el acceso. En vez de pegar el esquema de tu base de datos dentro del prompt cada mañana, expones la fuente y dejas que el agente la consulte cuando la necesite. Eso es lo que resuelven los servidores de Model Context Protocol: el contexto deja de ser algo que copias y pasa a ser algo que se consulta.

    Eso sí, cada servidor que conectas mete sus definiciones de herramientas en la ventana. MCP cambia copiar por consultar, no elimina el coste de contexto: conecta los que uses, no los que tengas.


    3. Implementación: del "en mi máquina funciona" al gate de salida

    Qué falla: preguntarle al agente si ha terminado.

    Te va a decir que sí. No porque mienta, sino porque no tiene forma de saberlo: está evaluando su propio trabajo con exactamente el mismo contexto con el que lo escribió. Si le faltaba una pieza para escribirlo bien, le sigue faltando para revisarlo.

    Necesitas una señal que venga de fuera del modelo. Y la señal más barata que existe es un código de salida.

    El bucle que uso:

    1. El agente escribe primero el test que falla.
    2. Escribe el código mínimo para que pase.
    3. El pipeline ejecuta tipado, tests y lint. Si sale 0, la tarea entra en la cola de revisión. Si no, el agente recibe el error y corrige sin que yo intervenga.

    El gate no tiene que ser un pipeline entero. Un script que encadene los tres comandos ya sirve: si devuelve 0, la tarea pasa; si no, el agente recibe el error y sigue solo.

    {
      "scripts": {
        "gate": "tsc --noEmit && bun test && bun run lint"
      }
    }
    

    Lo importante no es que sea TDD de manual. Es que la condición de parada la decide un proceso externo y no una frase del agente. Mientras la puerta de calidad seas tú leyendo la terminal, no has automatizado nada: solo has cambiado de sitio el cuello de botella.

    El flujo completo de validar código generado antes de mergear lo desarrollé en TDD con IA. Y si lo que quieres es probar al propio agente en CI —no solo al código que produce— eso es un test harness, que es una pieza distinta.

    Y ojo con el nivel de la suite, porque aquí hay un efecto perverso: unos tests flojos no son neutros. Le dan al agente permiso para dar por terminado un trabajo a medias, con la ventaja de que ahora el sello de aprobado es automático.


    4. Code review: del "a mí me parece bien" al diff acotado

    Qué falla: el volumen. Un agente produce en veinte minutos más código del que puedes revisar con atención en una tarde.

    Y aquí hay una trampa que cuesta ver: la calidad de tu code review se decide en la fase 1, no en la fase 4. Un diff de once archivos es muy difícil de auditar bien, y la razón por la que toca once archivos es que la spec no dijo cuáles no tocar. Cuando el alcance está escrito, el diff sale acotado solo, y revisarlo pasa de ser una tarde a ser un rato.

    Con el diff ya acotado, la revisión se reparte en dos filtros:

    • El automático, primero. Tipado, tests, lint y un auditor que mire el diff antes que tú. Lo que no pasa esos gates no llega a tus ojos. Cómo montarlo en el pipeline lo detallé en revisiones de código con IA en CI/CD.
    • El tuyo, después, y solo para lo que la máquina no puede ver. Que la abstracción elegida sea la correcta. Que no haya duplicado algo que ya existía. Que el error se maneje donde tiene sentido y no donde resultaba cómodo.

    Esa segunda lista es más larga de lo que parece, y hay fallos del código generado por IA que un code review directamente no ve. Los tests cubren la corrección. Tú cubres el criterio.

    El checklist que uso para auditar diffs generados por IA antes de mergear está en el ebook gratuito Revisión por Contrato.


    5. Documentación: del wiki muerto al contexto versionado

    Qué falla: guardar la arquitectura en herramientas que el agente no puede abrir.

    El contexto tiene que vivir en el repositorio, al lado del código y bajo control de versiones, en cuatro capas de artefactos de contexto para agentes que hacen cosas distintas:

    • CLAUDE.md o AGENTS.md en la raíz. Convenciones, comandos de build, qué no se toca. AGENTS.md es un formato abierto supervisado por la Agentic AI Foundation, bajo la Linux Foundation, y lo usan ya más de 60.000 proyectos open source. Es lo primero que lee el agente al arrancar y lo que evita la mayoría de los "esto no va aquí".
    • docs/adr/ con decisiones de arquitectura. Markdown ligero que explica por qué se decidió algo, no solo qué se decidió. Sin el porqué, el agente deshace tus decisiones creyendo que mejora el código.
    • Un índice consultable del conocimiento previo. Para que pueda buscar en lo que ya existe sin que le metas el proyecto entero en la ventana.
    • Un mapa de dependencias del repositorio. Qué depende de qué. Es la diferencia entre un agente que cambia una función y otro que sabe qué se rompe al cambiarla, y va de graph engineering.

    Con una advertencia importante, porque es el error clásico de quien descubre esto: más contexto no es mejor contexto. Llenar la ventana de documentación irrelevante degrada las respuestas igual que no tener nada, solo que gastando más. Cómo estructurar esa memoria para que sume está en context engineering aplicado a agentes, y qué pasa cuando la conversación se alarga demasiado, en context drift.


    La regla del eslabón más débil de tu SDLC

    La regla del eslabón más débil dice que tu ciclo rinde lo que rinda su fase peor: da igual lo bien que hagas las otras cuatro, el resultado del agente lo marca la fase rota.

    Por eso esta es la parte práctica, la que decide por dónde empezar mañana:

    • Specs impecables sin gate de tests: el agente escribe muy rápido algo que nadie valida.
    • Tests excelentes con tickets ambiguos: validas a la perfección la funcionalidad equivocada.
    • Todo bien montado y el conocimiento en tu cabeza: cada mañana empiezas de cero.

    Así que no empieces por la fase que más te apetece, que suele ser la que ya haces bien. Empieza por la que te está costando dinero ahora mismo. Este diagnóstico lo resuelve en un minuto:

    Lo que te pasa con el agente Fase que tienes rota
    Se sale del alcance y toca archivos que no debía 1. Requisitos
    Inventa campos, funciones o rutas que no existen 2. Diseño
    Dice que ha terminado y no funciona 3. Implementación
    Los diffs son tan grandes que no los revisas 4. Code review
    Repite errores que ya corregiste la semana pasada 5. Documentación

    Ese último síntoma es el más frecuente y el que más gente confunde con un problema de memoria del modelo. No lo es. Es que la corrección se quedó en el chat en vez de acabar en un archivo del repositorio.


    Lo que no debes hacer

    Documentarlo todo.

    Es la reacción típica cuando alguien entiende esta idea: se pasa un fin de semana escribiendo un CLAUDE.md de cuarenta secciones y una carpeta de ADRs preciosa. Tres meses después, la mitad ya no es verdad.

    Y contexto desactualizado es peor que no tener contexto, porque el agente lo obedece. Un archivo que dice que los servicios van en una carpeta que ya no existe no es un documento inútil: es una instrucción activa para hacerlo mal.

    La regla que aplico: si no lo vas a mantener, no lo escribas. Es preferible un archivo de quince líneas verdaderas que uno de doscientas donde no sabes cuáles siguen siéndolo.

    Tampoco todo proyecto necesita este aparato montado. Hay casos concretos en los que el enfoque de spec te frena, y conviene reconocerlos antes de meter ceremonia donde no hace falta.


    Los 3 cambios para tu próximo ticket

    No hace falta rehacer la metodología de tu equipo. En la próxima tarea que delegues:

    1. Escribe el "fuera de alcance". Una línea diciendo qué archivos no debe tocar el agente. Es el cambio con mejor retorno de esta lista.
    2. Pon un gate automático. Aunque sea solo tsc --noEmit y los tests. Que la respuesta a "¿ha terminado?" la dé un código de salida y no una frase.
    3. Mueve una convención de tu cabeza al repositorio. Una. La que más veces has tenido que repetirle al agente esta semana.

    Con esos tres, el siguiente prompt que escribas tiene muchas más probabilidades de salir a la primera sin que le cambies ni una palabra. Porque no habrás mejorado el prompt: habrás mejorado la fábrica que lo alimenta. Eso es SDLC context engineering.

    El flujo completo, de la idea al producto con herramientas agénticas, lo enseño paso a paso en el curso Construye con IA con Claude Code.

    Y si quieres ver los artefactos reales —specs, gates y archivos de contexto de proyectos que están en producción— eso es lo que compartimos cada semana en Dominicode Labs.

    Deja de buscar el prompt mágico. Arregla la fase que tienes rota y el contexto se arregla solo.


    Preguntas frecuentes

    ¿Qué es exactamente el SDLC context engineering?

    Es tratar tu ciclo de vida del software como el sistema que fabrica el contexto de tus agentes de IA. En lugar de escribir prompts cada vez más largos, haces que cada fase del ciclo —requisitos, diseño, implementación, revisión y documentación— deje un artefacto que una máquina pueda leer y verificar: una spec con límites, un esquema de validación, una suite de tests, un diff acotado y contexto versionado en el repositorio.

    ¿Esto no es lo mismo que el prompt engineering?

    No, y la diferencia es de escala. El prompt engineering trabaja sobre la instrucción concreta que escribes en un turno. El context engineering trabaja sobre la información que esa instrucción tiene disponible, y esa información la produce tu proceso, no tú en el momento de escribir. Un buen prompt sobre un ciclo roto sigue dando resultados malos, solo que con mejor redacción.

    ¿Por dónde empiezo si tengo las cinco fases mal?

    Por el síntoma que estés sufriendo ahora, no por el orden numérico. Si el agente se sale del alcance, empieza por la spec. Si inventa campos que no existen, por los contratos de datos. Si dice que ha terminado y no funciona, por el gate de tests. La cadena rinde lo que rinda su fase peor, así que arreglar la que más te está costando da más retorno que mejorar la que ya funciona.

    ¿Hace falta usar Spec-Driven Development para esto?

    No es obligatorio, pero la fase de requisitos es la que más impacto tiene sobre las otras cuatro, y SDD es la forma más ordenada de resolverla. Puedes empezar con algo mucho más ligero: una línea de "fuera de alcance" en el ticket ya cambia el comportamiento del agente. Y hay casos concretos en los que el enfoque de spec te frena en vez de ayudarte, así que conviene reconocerlos antes de montar ceremonia.

    ¿Cuánto contexto es demasiado contexto?

    El que no puedas mantener actualizado. Un archivo de contexto que ya no refleja la realidad no es neutro: el agente lo obedece y hace las cosas mal con total seguridad. La medida correcta no es cuántas páginas tienes, sino cuántas líneas puedes garantizar que siguen siendo ciertas hoy. Además, llenar la ventana de contexto irrelevante degrada las respuestas y encarece cada turno.

    ¿Qué documentación para agentes de IA hace falta de verdad en un repositorio?

    Cuatro capas y nada más: un CLAUDE.md o AGENTS.md en la raíz con convenciones y comandos, una carpeta docs/adr/ con el porqué de las decisiones de arquitectura, un índice consultable del conocimiento previo y un mapa de dependencias del repositorio. Todo versionado junto al código. Lo que no esté en el repositorio, el agente no lo puede abrir.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • La factura del vibe coding: improvisar con un agente sale 7 veces más caro

    La factura del vibe coding: improvisar con un agente sale 7 veces más caro

    "Añade suscripciones con Stripe, cupones de descuento y control de acceso por roles."

    Un prompt. Diecisiete palabras. El agente arrancó con entusiasmo: creó catorce archivos, instaló tres dependencias que no hacían falta, inventó un esquema de base de datos incompatible con el que ya existía y, hacia el paso dieciocho, se puso a arreglar errores de compilación que había provocado él mismo seis pasos antes.

    Cuarenta y cinco minutos después, git reset --hard. Salía más a cuenta tirarlo todo que rescatarlo.

    Esa historia —el vibe coding en estado puro— la hemos vivido todos, y siempre se cuenta igual: en tiempo perdido y en frustración. Nadie mira la otra columna.

    Lo que nadie miró ese día fue la factura. Y es la parte más fácil de calcular, la más incómoda de ver y la que convence a un jefe en treinta segundos, que es más de lo que ha conseguido nunca el argumento de "escribir la spec es buena práctica".

    De qué es SDD, qué lleva dentro un spec.md y cómo se genera el plan.md no voy a hablar aquí: está en por qué Spec-Driven Development triplica tu velocidad. Este post hace una sola cosa: poner precio a improvisar.


    La factura no crece con los turnos: crece con su cuadrado

    Aquí está la parte que casi nadie tiene interiorizada, y sin ella todo el cálculo parece exagerado.

    Un agente no manda tu último mensaje: manda toda la conversación otra vez, en cada turno. Lo que escribiste al principio, la salida de aquel grep, el test que falló en el turno 3. Todo, cada vez.

    Si cada turno añade d tokens al contexto y la sesión dura n turnos, lo que pagas no es n × d. Es esto:

    total = n · base  +  d · n · (n − 1) / 2
                         └──────┬─────────┘
                         el término que te mata
    

    Ese segundo término es cuadrático. En cristiano: duplicar los turnos de una sesión no duplica la factura, la multiplica por casi cuatro. El mecanismo, con la instrumentación para medirlo en tu propio agente, lo desglosé en medir el consumo de tokens de un agente.

    Y ahora la pregunta que conecta las dos mitades del post: ¿qué hace una especificación, exactamente?

    Reduce n.

    No hace al modelo más listo ni al código más bonito. Solo elimina turnos: los de explorar el repositorio a ciegas, los de elegir una librería y cambiarla, los de deshacer, los de arreglar lo que rompió al deshacer. Y como la factura va con el cuadrado de los turnos, quitar turnos por delante es la palanca más potente que existe.


    Las dos sesiones, en números

    Cojamos la sesión de Stripe de arriba y su versión con spec. Mismo modelo, mismo repositorio, misma persona.

    Los supuestos, sobre la mesa antes que los resultados:

    • 6.000 tokens de base por turno: system prompt, definiciones de herramientas, archivos abiertos.
    • 6.000 tokens que se añaden en cada turno: el diff, la salida del test, lo que devuelve cada herramienta.
    • La spec ocupa 2.500 tokens y se paga en todos los turnos, porque viaja en el contexto entera.
    • 18 turnos improvisando, 6 con la spec delante.
    • Precio de entrada: 5 $ por millón de tokens.
    Vibe coding Con spec
    Turnos 18 6
    Base por turno 6.000 8.500 (incluye la spec)
    Tokens de input acumulados 1.026.000 141.000
    Coste de entrada 5,13 $ 0,71 $

    Siete veces. Y no por un truco: los 141.000 son el 13,7 % de 1.026.000, así que el ahorro es del 86 %.

    Fíjate en el detalle que hace daño: los 2.500 tokens de la spec, multiplicados por los seis turnos, suman 15.000 tokens de sobrecoste. Un solo turno tardío de la sesión improvisada —el turno 18, con todo el historial detrás— cuesta 108.000. La especificación se paga siete veces con evitar un único turno al final.

    Estos números son un modelo, no una medición de laboratorio: salen de aplicar la fórmula de arriba a los supuestos declarados. Cambia los tuyos y cambiarán los resultados. Lo que no cambia es la forma de la curva, porque el término cuadrático no depende del precio: si el ratio de turnos es 3 a 1, el ratio de coste ronda 7 a 1 pagues lo que pagues — y llega a 8 a 1 si no cuentas lo que ocupa la propia spec.


    De dónde salen los doce turnos que te ahorras

    No son turnos imaginarios. Son estos, y los reconocerás todos:

    • Reconocimiento. Sin spec, el agente abre archivos "por si acaso" para deducir tu arquitectura. Con la spec, ya sabe qué toca y qué no.
    • Decisiones que tú deberías haber tomado. Elige una librería, la instala, no encaja, la quita. Tres turnos que se resolvían con una línea en el documento.
    • Marcha atrás. Descubre en el turno 12 que el esquema de base de datos no cuadra con lo que ya existe y rehace lo del turno 5.
    • Parches sobre parches. Arregla un error de compilación creando otro, porque ya no recuerda la restricción del primer mensaje.

    Los dos últimos tienen la peor propiedad de todas: son los turnos más caros de la sesión, porque ocurren al final, cuando el contexto ya pesa. En una sesión de 18 turnos, los seis últimos se llevan más de la mitad de la factura.

    Ojo con la conclusión fácil, eso sí: una spec ambigua o incompleta no ahorra nada, porque el agente vuelve a decidir por su cuenta y los turnos regresan. Por qué una especificación falla y qué la hace inservible lo conté en por qué tu spec falla con un agente de IA.

    Y hay un caso en el que este cálculo se da la vuelta: cuando el trabajo es tan pequeño que escribir la spec cuesta más turnos que hacerlo. Los seis escenarios donde no compensa están en cuándo NO usar Spec-Driven Development.


    Cómo medir esto en tu repositorio esta semana

    No hace falta creerme. Tienes los datos en tu historial:

    1. Cuenta los turnos de tus últimas cinco sesiones con el agente. Solo el número, nada más.
    2. Sepáralas en dos montones: las que empezaron con un documento delante y las que empezaron con una frase.
    3. Aplica la fórmula con tu base y tu delta reales, que los saca la instrumentación del post de consumo de tokens en media hora.
    4. Multiplica por sesiones al mes. Ahí es donde el número deja de ser una curiosidad y pasa a ser una cifra de la que hablar en una reunión.

    Si además pagas por suscripción y no por API, el cálculo sigue valiendo: no cambia la factura, cambia cuántas sesiones te caben antes de tocar el límite de uso.

    El flujo completo —de la idea a la spec, y de la spec al agente ejecutando por fases— lo enseño paso a paso en el curso Construye con IA: de la idea al producto con Claude Code, y como referencia de consulta está el libro de Spec-Driven Development.

    Una última pieza, porque es la que cierra el círculo: el agente no puede dar una tarea por terminada porque "el código parece correcto". Necesita un test que devuelva 0, y para eso hacen falta suites rápidas y fiables — que es lo que trabajo en el curso de Testing en Angular con Jest y Testing Library. Sin esa comprobación, los turnos de marcha atrás vuelven por la puerta de atrás y con ellos la factura.

    En Dominicode Labs trabajamos así todos los proyectos de la comunidad.

    Escribir la especificación no es burocracia ni buena práctica de manual. Son 2.500 tokens que te ahorran un millón.


    Preguntas frecuentes

    ¿El prompt caching no se come todo este ahorro?

    Lo reduce, no lo elimina. La caché abarata el reenvío del historial ya visto, así que el término cuadrático pasa a costar una fracción — pero solo mientras el prefijo se mantenga idéntico. Y una sesión improvisada es justo la que peor lo mantiene: cada marcha atrás reescribe contexto anterior e invalida la caché a partir de ahí. Con caché el 8 a 1 se estrecha; la dirección no cambia.

    ¿Cuántos tokens puede ocupar la spec para que siga saliendo a cuenta?

    Muchos más de los que vas a escribir. La spec se suma a la base y por tanto cuesta tokens × turnos; un turno tardío evitado cuesta base + delta × (n−1). Con los supuestos de este post, una spec de 10.000 tokens en una sesión de seis turnos sale por 60.000, todavía por debajo de lo que costaba aquel turno 18 en solitario. El límite práctico no es económico: es que una spec larga se lee peor y decide peor.

    ¿Y si trabajo con suscripción en vez de pagar por token?

    El coste cambia de moneda, no desaparece. Con tarifa plana pagas en cuota de uso y en tiempo de espera: la misma sesión cuadrática te consume el límite antes y te deja mirando el reloj. La ventaja de medirlo en tokens es que es la única unidad que no depende de la tarifa que tengas contratada.

    Si la spec está mal escrita, ¿ahorra igual?

    No, y este es el fallo más común. Una spec con huecos —sin decir qué queda fuera de alcance, sin contratos de datos, sin nombrar los archivos que se tocan— devuelve las decisiones al modelo, y con ellas vuelven los turnos de exploración y marcha atrás. Una especificación ambigua tiene el coste de escribirla y ninguno de sus beneficios.

    ¿Merece la pena para un cambio de veinte líneas?

    No. Para un bug acotado o un ajuste de copy, el trabajo cabe en dos o tres turnos y ahí el término cuadrático no ha despegado todavía: la spec es sobrecoste puro. Este cálculo empieza a inclinarse a partir de las sesiones largas, que son precisamente las que hoy nadie planifica.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Roadmap del developer con IA: de junior a fullstack agentic

    Roadmap del developer con IA: de junior a fullstack agentic

    En 2011 mi trabajo diario como programador consistía en memorizar la sintaxis de jQuery, lidiar con los bugs de Internet Explorer 8 y escribir bucles for a mano.

    Si en aquel momento alguien me hubiera dicho que 15 años después un modelo de lenguaje escribiría un algoritmo completo en dos segundos, habría pensado que la profesión de programador iba a desaparecer de la faz de la tierra.

    La realidad ha sido muy distinta, y por eso el roadmap del developer con IA no se parece en nada al de hace cinco años: programar no ha muerto, pero el acto de mecanografiar código se ha convertido en un commodity.

    El desarrollador que solo sabe traducir un ticket de Jira a líneas de JavaScript está en una posición vulnerable. En cambio, el perfil que está multiplicando su valor en el mercado es el Fullstack Agentic Developer: el profesional que diseña la arquitectura, establece los contratos y dirige un ejército de agentes de IA para construir productos en tiempo récord.

    Aquí tienes la hoja de ruta clara para hacer esa transición.


    La Evolución del Perfil: De Codificador a Director de Agentes

    ┌─────────────────────────────────────────────────────────────┐
    │               EVOLUCIÓN DEL ROL DE DEVELOPER                │
    │                                                             │
    │  AYER (Programador Tradicional)                            │
    │  [Escribir sintaxis] ──> [Recordar APIs] ──> [Debug manual] │
    │                                                             │
    │  HOY & MAÑANA (Agentic Developer)                           │
    │  [Diseñar Specs] ──> [Dirigir Agentes/MCP] ──> [TDD & CI]   │
    └─────────────────────────────────────────────────────────────┘
    

    La ventaja competitiva ya no es recordar de memoria los parámetros de un método de array. Tu valor reside en tu criterio técnico para decidir qué construir, con qué arquitectura y bajo qué límites de seguridad.


    Las 4 Habilidades Indispensables para los Próximos 3 Años

    1. Spec-Driven Development (SDD) y Diseño de Contratos

    Tu capacidad para redactar especificaciones técnicas precisas (spec.md) determinará la calidad del software que generen tus agentes. Si no sabes definir límites de dominio, flujos de datos y escenarios WHEN/THEN, los modelos alucinarán y perderás horas corrigiendo código basura.

    Es la habilidad con más retorno de las cuatro. Si empiezas hoy, empieza por aquí: Spec-Driven Development con agentes de IA.

    2. Fundamentos Sólidos de Arquitectura y Tipado Estricto

    Para evaluar si el código generado por un agente es seguro para producción necesitas dominar:

    • Clean Architecture y separación de capas (Domain, Application, Infrastructure).
    • TypeScript estricto, tipos discriminados y esquemas de validación en runtime con Zod.
    • Patrones de concurrencia y diseño de bases de datos relacionales.

    3. Testing Automatizado y Validación Determinista (TDD)

    La IA es probabilística; el software de producción debe ser determinista. La única forma de desplegar a producción sin miedo es contar con suites de pruebas automatizadas con Vitest o Jest que actúen como un guardián implacable ante cualquier regresión.

    4. Orquestación de Agentes, Herramientas y Protocolos MCP

    Aprender a conectar agentes CLI (como Claude Code) con bases de datos, APIs de terceros y herramientas de terminal mediante el Model Context Protocol (MCP) y la creación de custom skills (SKILL.md).

    El salto de nivel aquí está en dejar de escribir prompts y empezar a construir herramientas: cómo crear skills y subagentes personalizados para que tu flujo diario se ejecute solo.


    La Hoja de Ruta (Roadmap) Paso a Paso

    FASE 1: Fundamentos Modernos
    ├── TypeScript 5+ Estricto (Satisfies, Discriminated Unions, Generics)
    ├── Frameworks Reactivos (Angular Signals / Next.js 16 App Router)
    └── Validación de Esquemas con Zod
    
    FASE 2: Red de Seguridad y Metodología
    ├── TDD con Vitest / Jest (Escribir tests antes de generar código)
    └── Flujo SDD (Spec ➔ Plan ➔ Tasks versionados en Git)
    
    FASE 3: Operaciones Agénticas
    ├── Dominio de agentes CLI (Claude Code, Cursor, terminal tools)
    ├── Creación de Custom Skills y Subagentes especializados
    └── Conexión de servidores MCP para acceso a bases de datos y APIs
    
    FASE 4: Producción y Negocio
    ├── Despliegues Serverless, Edge Functions y bases de datos relacionales
    └── Entrega continua (CI/CD) con validación automática de agentes
    

    Para recorrer este camino con proyectos prácticos de extremo a extremo, en el curso Construye con IA: De la Idea al Producto con Claude Code te guiamos paso a paso en la transición hacia el desarrollo agentico.

    Si buscas una comunidad activa donde compartimos arquitecturas reales, plantillas de agentes y debates técnicos semanales, únete a Dominicode Labs.

    También puedes seguir todos nuestros tutoriales y directos gratuitos en el Canal de YouTube de Dominicode.


    Qué hacer hoy con esto

    Elige un proyecto personal o una tarea pequeña de tu trabajo.

    No intentes escribir cada línea de código a mano por nostalgia, ni tampoco le pidas a la IA que haga todo sin supervisión.

    Asume el rol de arquitecto: redacta la especificación, diseña los tests de validación y delega la implementación sintáctica a tu agente. Ese es el nuevo estándar de la ingeniería de software.


    Preguntas frecuentes

    ¿Los agentes de IA van a sustituir a los desarrolladores juniors?

    No van a sustituir a los desarrolladores, pero sí sustituirán el modelo tradicional de trabajo junior basado exclusivamente en escribir sintaxis básica. Los juniors que adopten metodologías estructuradas (SDD, TDD) y aprendan a orquestar agentes avanzarán mucho más rápido hacia niveles senior.

    ¿Por qué aprender TypeScript y testing si la IA puede escribir el código?

    Porque la IA comete errores sutiles y alucinaciones. Sin conocimientos profundos de TypeScript y testing automatizado, no tendrás el criterio técnico necesario para auditar el código generado ni detectar fallos antes de que lleguen a producción.

    ¿Qué es un Servidor MCP (Model Context Protocol)?

    Es un estándar abierto desarrollado por Anthropic que permite a los asistentes de IA conectarse de forma segura con herramientas locales, bases de datos (Postgres, SQLite), repositorios Git y APIs de servicios externos.

    ¿Cuánto se tarda en recorrer este roadmap?

    Depende del punto de partida, pero las cuatro fases no son secuenciales en el tiempo: puedes empezar a escribir specs y tests la semana que viene mientras sigues consolidando fundamentos. Lo que no funciona es saltar a la Fase 3 sin las dos primeras, porque sin criterio técnico no puedes auditar lo que el agente produce.

    ¿Hace falta ser senior para trabajar con agentes de código?

    No, pero sí hace falta saber leer código mejor de lo que lo escribes. Un junior que domina testing y sabe redactar una especificación clara saca más partido a un agente que un senior que le pide código a ciegas y acepta el diff sin revisarlo.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Integrar OpenSpec con Claude Code: el flujo OPSX paso a paso

    Integrar OpenSpec con Claude Code: el flujo OPSX paso a paso

    El lunes le pedí a Claude Code que añadiera paginación a un listado. Lo hizo bien.

    El miércoles abrí una sesión nueva en el mismo proyecto y le pedí un filtro. Se inventó otra forma de paginar, distinta a la del lunes, y reescribió la que ya funcionaba.

    No fue culpa del modelo. El contexto de Claude Code vive en la sesión: cierras la terminal y se evapora.

    OpenSpec con Claude Code resuelve eso. OpenSpec es un framework open source de spec-driven development creado por Fission-AI que guarda lo acordado — propuesta, diseño, tareas y spec — en archivos Markdown versionados dentro del repo, para que Claude Code los lea antes de tocar código. En esta guía lo instalamos, lo inicializamos con openspec init y recorremos el flujo OPSX completo sobre un proyecto que ya existe.


    OpenSpec no es OpenAPI: la diferencia en una tabla

    Comparten cuatro letras y nada más.

    OpenSpec OpenAPI
    Qué es Framework de spec-driven development para asistentes de código Especificación para describir APIs REST
    Quién lo mantiene Fission-AI OpenAPI Initiative (Linux Foundation)
    Formato Markdown dentro del repo YAML o JSON
    Para qué sirve Que un agente implemente lo acordado Que un cliente sepa llamar a tu API

    Si has llegado buscando Swagger, este no es tu post.


    Cómo instalar OpenSpec para Claude Code (y el error de scope de npm)

    OpenSpec se instala como CLI global. Requiere Node.js 20.19.0 o superior, y la versión actual es la 1.8.0.

    npm install -g @fission-ai/openspec@latest
    

    Fíjate bien en el scope, porque esto:

    # ❌ NO es OpenSpec
    npm install -g openspec
    

    instala otro paquete distinto: openspec a secas es la versión 0.0.0 publicada el 9 de abril de 2019, sin relación alguna con el framework y sin una sola actualización desde entonces. Es el fallo más repetido en tutoriales, y luego pasas media hora preguntándote por qué openspec init no hace lo que dice la documentación.

    Instala siempre el paquete con scope @fission-ai/.


    Qué crea openspec init en un proyecto con Claude Code

    Desde la raíz del repo:

    cd tu-proyecto
    openspec init
    

    El init te pregunta qué herramienta usas. Selecciona Claude Code.

    Y aquí el detalle que casi nadie explica bien: para Claude Code te crea las dos cosas.

    .claude/skills/openspec-*/SKILL.md    ← una skill por cada acción del flujo
    .claude/commands/opsx/<id>.md         ← los slash commands
    openspec/config.yaml                  ← la configuración del proyecto
    

    Las skills las carga Claude Code solo, sin que tú hagas nada. Los comandos son la puerta de entrada manual cuando quieres disparar una fase concreta. No eliges entre unas y otros: conviven.

    El config.yaml guarda además tus preferencias entre ejecuciones de init y update. Si mañana actualizas OpenSpec, no te vuelve a preguntar todo.


    Qué poner en openspec/config.yaml (y por qué no es opcional)

    openspec/config.yaml es el archivo donde defines el schema por defecto, el contexto del proyecto y las reglas por artefacto. No es documentación que el agente abre si le apetece: es entrada del modelo. La doc oficial lo dice sin rodeos — "When generating any artifact, your context and rules are injected into the AI prompt".

    Sus claves de nivel superior son cuatro:

    Clave Para qué
    schema El schema por defecto de los artefactos
    context La información de tu proyecto. Aparece en todos los artefactos
    rules Restricciones por artefacto. Solo aparecen en el artefacto que coincide
    operations Guía opcional para apply y archive

    Ese matiz de context y rules importa: el contexto viaja siempre, las reglas solo cuando toca. Así que lo que quieras que el agente tenga presente en cada decisión va en context.

    Dedica cinco minutos a describir de verdad tres cosas ahí: el stack real con sus versiones, las convenciones que sigues (naming, estructura de carpetas, patrón de tests) y lo que está prohibido en el proyecto — esa librería que ya migraste, ese patrón que odias.

    La diferencia se nota en la primera propuesta. Con el config vacío recibes una propuesta genérica de manual. Con el config bien puesto recibes una que usa tus carpetas, tus nombres y tu forma de testear. El detalle de cada clave está en la doc de customization.

    Es la misma lógica que trabajamos en el curso Construye con IA: el resultado de un agente depende mucho menos del prompt del momento que del contexto estable que le dejaste montado antes.


    El flujo OPSX paso a paso en Claude Code

    En Claude Code los comandos van con dos puntos: /opsx:<id>. Este detalle importa y ahora verás por qué.

    /opsx:explore — pensar sin comprometerte

    /opsx:explore
    

    Fase de planificación pura. Exploras el problema, discutes enfoques, descartas caminos. No genera artefactos ni te ata a nada.

    Es el comando que más se omite en los tutoriales y el que más rentabilidad da. Cuando saltas directo a propose, el agente propone algo — y lo propone bien argumentado, con lo cual te lo crees. En explore es donde descubres que el problema real era otro, antes de tener cuatro archivos que revisar.

    /opsx:propose — generar la propuesta

    /opsx:propose añadir filtros por categoría al listado de productos
    

    Aquí se materializa el trabajo:

    openspec/changes/<nombre-del-cambio>/
    ├── proposal.md    ← qué se va a hacer y por qué
    ├── design.md      ← cómo, a nivel técnico
    ├── tasks.md       ← el desglose ejecutable
    └── specs/         ← la delta spec del cambio
    

    Y ahora tu parte: leerlo. Este es el punto exacto donde el flujo funciona o no funciona. Corriges asunciones, ajustas el diseño, partes tareas demasiado grandes. Cuesta minutos ahora y ahorra horas después.

    /opsx:apply — implementar contra la spec

    /opsx:apply
    

    El agente implementa tarea por tarea, referenciando la spec acordada. La diferencia con pedirle código a pelo es que ya no hay margen de interpretación.

    /opsx:archive — cerrar el cambio

    /opsx:archive
    

    Mueve el cambio a openspec/changes/archive/ y consolida lo implementado en openspec/specs/, que es la fuente de verdad del proyecto — "Specs are the source of truth — they describe how your system currently behaves". A partir de ahí eso ya no es un cambio pendiente: es cómo funciona tu sistema.

    Los otros dos del perfil por defecto

    /opsx:update revisa los artefactos de planificación de un cambio y los mantiene coherentes entre sí, en cualquier dirección: si editas el diseño, la propuesta se ajusta.

    /opsx:sync fusiona las delta specs en openspec/specs/ sin archivar el cambio. Útil cuando quieres consolidar antes de cerrar.

    Los extendidos, y por qué /opsx:verify no te va a funcionar todavía

    Aquí está el detalle que hace perder media hora a mucha gente: el perfil por defecto no trae verify.

    El perfil core son los seis de arriba — propose, explore, apply, update, sync, archive. Los extendidos son otros seis: /opsx:new, /opsx:continue, /opsx:ff, /opsx:verify, /opsx:bulk-archive y /opsx:onboard. Si escribes /opsx:verify recién instalado, no autocompleta y no pasa nada.

    Para activarlos:

    openspec config profile   # selecciona el perfil ampliado
    openspec update           # aplica los cambios en el proyecto
    

    Con el perfil ampliado activo, /opsx:verify contrasta la implementación contra la spec. No es un test runner: es la comprobación de que no se ha colado nada que nadie pidió y de que no falta nada que sí se pidió.

    Empieza por los seis del perfil core. Los extendidos los necesitarás cuando tengas el ciclo rodado y lleves varios cambios a la vez.


    Delta specs: por qué esto sirve en un proyecto que ya existe

    Una delta spec es una spec que describe solo lo que cambia — lo añadido, lo modificado y lo eliminado — en vez de redescribir el sistema entero. Es lo que hace viable OpenSpec en un proyecto que ya existe.

    Así se ve una:

    ## ADDED Requirements
    
    ### Requirement: Filtrado por categoría
    El listado DEBE permitir filtrar productos por categoría.
    
    #### Scenario: Usuario selecciona una categoría
    - GIVEN el listado de productos cargado
    - WHEN el usuario selecciona la categoría "Audio"
    - THEN el listado muestra solo productos de esa categoría
    
    ## MODIFIED Requirements
    
    ### Requirement: Paginación del listado
    El listado DEBE conservar el filtro activo al cambiar de página.
    

    Dos cosas que conviene saber antes de copiar esto. Las etiquetas son literales y no se traducen: ADDED, MODIFIED, REMOVED, Requirement:, Scenario: y GIVEN/WHEN/THEN van en inglés aunque el cuerpo esté en español. Y solo incluyes las secciones que uses — si el cambio no elimina nada, no dejes un ## REMOVED Requirements vacío.

    Sobre los escenarios: es vocabulario Gherkin, pero en Markdown plano. Sin ficheros .feature, sin Cucumber, sin plugins.

    Piensa en la alternativa: especificar entera una aplicación con tres años de historia para poder añadir un filtro. No lo hace nadie, y por eso la mayoría de intentos de SDD en brownfield mueren en la segunda semana. Con deltas, la unidad de trabajo es el cambio, no el sistema.

    Si quieres el marco completo detrás de esto — cómo se escribe una spec que un agente pueda ejecutar sin rellenar huecos por su cuenta — lo desarrollo en el libro de Spec-Driven Development.

    Y para el reverso de la moneda, ya escribí sobre por qué una spec falla con un agente de IA.


    La sintaxis cambia según la herramienta

    Dato práctico que ahorra confusión cuando copias comandos de un tutorial grabado con otro editor:

    Herramienta Sintaxis
    Claude Code /opsx:propose
    Cursor /opsx-propose
    GitHub Copilot /opsx-propose
    Amazon Q @opsx-propose
    Codex $openspec-propose

    Mismo flujo, distinto prefijo. Si el comando no autocompleta en tu editor, casi siempre es esto. La lista completa está en la tabla de herramientas soportadas, que cubre más de treinta.


    Cómo migrar del flujo antiguo de OpenSpec al flujo OPSX

    El flujo pre-OPSX está muerto. Pasó de fases cerradas a acciones, y la traducción es esta:

    Antes Ahora
    /openspec:proposal /opsx:propose
    openspec/project.md openspec/config.yaml
    changes/active/ openspec/changes/

    Si tienes un proyecto con la estructura antigua, no lo migres a mano: ejecuta openspec update, que regenera los ficheros de skills y comandos para las herramientas que tengas configuradas.


    Qué hacer hoy con esto

    Abre un proyecto que ya tengas — uno real, con código feo dentro — y no empieces por una feature grande.

    Instala, ejecuta openspec init, dedica cinco minutos de verdad al config.yaml y lanza un /opsx:explore sobre el próximo cambio pequeño que tenías pendiente. Sigue hasta /opsx:archive. Media hora, un ciclo completo.

    Dos avisos antes de que te lances. Esto no sustituye a revisar el código: sustituye a discutir el mismo diseño tres veces. Y no todo cambio merece el ciclo completo — un fix de dos líneas no necesita una propuesta, y sobre eso escribí en cuándo NO usar spec-driven development.

    Si quieres ver este flujo aplicado a proyectos completos, con los casos donde se rompe y cómo se arregla, lo trabajamos dentro de Dominicode Labs.

    Lo que vas a notar no es velocidad. Es que la siguiente sesión de Claude Code arranca sabiendo lo que se decidió en la anterior. Eso es lo que compras aquí.


    Preguntas frecuentes

    ¿OpenSpec es lo mismo que OpenAPI?

    No. OpenSpec es un framework open source de spec-driven development para asistentes de código, creado por Fission-AI. OpenAPI es una especificación para describir APIs REST. Comparten cuatro letras y nada más.

    ¿Por qué mi instalación de OpenSpec no funciona?

    Lo más probable es que hayas instalado el paquete equivocado. El comando correcto es npm install -g @fission-ai/openspec@latest, con el scope @fission-ai. El paquete llamado openspec a secas es otro proyecto distinto, y es el error que arrastran muchos tutoriales antiguos.

    ¿OpenSpec sirve en un proyecto que ya existe o solo en proyectos nuevos?

    Sirve en proyectos existentes, y esa es su mejor característica. La spec de cada cambio es una delta: solo describe lo que se añade, se modifica o se elimina, con las secciones ADDED, MODIFIED y REMOVED Requirements. No necesitas especificar tu sistema entero para empezar.

    ¿Se puede usar OpenSpec con Cursor o Copilot en vez de Claude Code?

    Sí. El flujo es el mismo y lo que cambia es el prefijo de los comandos. Claude Code usa /opsx:propose con dos puntos, Cursor y Copilot usan /opsx-propose con guion, Amazon Q usa @opsx-propose y Codex usa $openspec-propose. Lo seleccionas al ejecutar openspec init.

    ¿Puedo saltarme el comando explore e ir directo a propose?

    Puedes, pero es donde más gente pierde tiempo. El comando explore es la fase de planificación sin compromiso y sirve para descartar enfoques antes de generar propuesta, diseño, tareas y spec. Si vas directo a propose, acabas revisando cuatro artefactos de una solución que quizá resuelve el problema equivocado.

    ¿Por qué no me funciona el comando /opsx:verify?

    Porque no viene en el perfil por defecto. OpenSpec usa el perfil core, que trae seis comandos: propose, explore, apply, update, sync y archive. El comando verify pertenece al perfil ampliado, junto a new, continue, ff, bulk-archive y onboard. Para activarlo ejecuta openspec config profile y después openspec update.

    ¿Qué comandos trae OpenSpec por defecto?

    El perfil core incluye seis: propose para generar la propuesta, explore para planificar sin compromiso, apply para implementar, update para mantener coherentes los artefactos de planificación, sync para fusionar las delta specs en openspec/specs/ y archive para cerrar el cambio.

    ¿Qué hago si seguí un tutorial con el flujo antiguo de OpenSpec?

    Ese flujo ya no es válido. El comando /openspec:proposal pasó a /opsx:propose, el archivo openspec/project.md pasó a openspec/config.yaml y la carpeta changes/active/ pasó a openspec/changes/. Lo más limpio es ejecutar openspec update en el proyecto, que regenera skills y comandos, en lugar de renombrar archivos a mano.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Los tres niveles de Spec-Driven Development (y por qué casi todos estamos en el primero)

    Los tres niveles de Spec-Driven Development (y por qué casi todos estamos en el primero)

    Hace unas semanas abrí un repo mío de febrero. Fui a la carpeta specs/. Ahí seguía todo: spec.md, plan.md, tasks.md.

    El spec.md describía tres endpoints. El código tenía once.

    La spec no estaba mal escrita. Estaba muerta. Cinco meses sin tocarla mientras el código crecía por su cuenta. Y lo peor es que todo funcionaba: los tests pasaban, el deploy iba, nadie se enteró de nada.

    Yo llevaba meses diciendo que hacía SDD. No lo hacía. Hay tres niveles de Spec-Driven Development y yo estaba en el primero convencido de estar en el segundo.

    Esto no va de qué es SDD. Va de diagnóstico: en qué nivel estás de verdad y a cuál te conviene subir. Que no siempre es el de arriba.

    El test de los 30 segundos: borra la carpeta specs/

    Antes de leer nada más, hazte esta pregunta.

    Si borras la carpeta specs/ de tu proyecto ahora mismo, ¿se rompe algo del pipeline?

    Si la respuesta es no —si el build sigue verde, los tests pasan y el deploy sale— entonces tu spec es un documento, no un artefacto de ingeniería. Eres spec-first. Da igual lo bien escrita que esté. Da igual que tengas constitution.md y siete plantillas.

    Nada que se pueda borrar sin consecuencias forma parte del sistema.

    Y ojo, que esto no es un insulto. Spec-first es un nivel legítimo y para la mitad de tus proyectos es exactamente el que necesitas. El problema no es estar ahí. El problema es estar ahí creyendo que estás dos escalones más arriba, y por tanto confiando en garantías que no tienes.

    Qué son los tres niveles de rigor de especificación

    Deepak Babu Piskala publicó el 30 de enero de 2026 el preprint Spec-Driven Development: From Code to Contract in the Age of AI Coding Assistants (arXiv:2602.00180, cs.SE). Es el primer sitio donde he visto puesto por escrito, con nombres, lo que la mayoría hacemos por intuición.

    El paper define tres niveles de rigor de especificación: spec-first, spec-anchored y spec-as-source. Lo único que cambia entre ellos es cuánta autoridad tiene la spec sobre el código — el eje de su primera figura se llama literalmente increasing specification authority.

    No son fases de madurez que haya que recorrer. Son opciones, y cada una tiene un coste.

    Nivel La spec es… ¿Quién escribe el código? ¿Qué pasa con el drift? Es tu nivel si…
    Spec-first Un briefing inicial Tú o el agente al arrancar; después, solo tú Ocurre en silencio, nadie se entera Prototipos, features puntuales, exploración
    Spec-anchored Un contrato vivo Tú, con la spec como referencia obligatoria Lo detecta el CI si lo automatizas; si no, rot La mayoría de sistemas en producción
    Spec-as-source El único artefacto que un humano edita Nadie. Se genera No existe por construcción Automoción, embebidos, dominios certificados

    Spec-first: la spec guía el arranque

    Definición del paper: la especificación se escribe antes de programar para guiar la implementación inicial.

    Ahí está la palabra clave: inicial. La spec hace su trabajo en el minuto cero y después su vida útil se acaba. El agente genera el código, tú lo revisas, y desde ese momento el código es la única fuente de verdad.

    El paper es explícito: spec-first funciona en desarrollo inicial de features con asistentes de IA, y en prototipos y features de usar y tirar.

    Es donde está casi todo el mundo que usa Claude Code o Cursor con un spec.md delante. Y para mucho de lo que hacemos, está perfecto. Escribes la spec, el agente construye, tú corriges, sigues adelante. Es el flujo que enseño en el curso de Construye con IA para ir de idea a producto sin caos.

    El fallo no es usar spec-first. El fallo es usar spec-first en un sistema que va a vivir tres años y con cuatro personas tocándolo.

    Spec-anchored: la spec vive con el código

    Definición del paper: la especificación se mantiene junto al código durante todo el ciclo de vida del sistema.

    Y aquí viene la frase que a mí me hizo replantearme cosas. El paper llama a spec-anchored el punto óptimo para la mayoría de sistemas en producción, porque te da los beneficios de documentación clara y requisitos verificables sin exigir que el código se genere entero.

    Traducido: tienes las garantías sin renunciar a escribir código.

    El riesgo de este nivel tiene nombre propio en el paper: specification rot. La podredumbre de la especificación, que aparece cuando los equipos no actualizan las specs a medida que el código cambia. Exactamente lo que le pasó a mi repo de febrero.

    Y la solución que propone el paper no es disciplina. Es automatización: los tests imponen la alineación entre spec y código, con escenarios BDD funcionando como tests automáticos que corren en cada commit.

    Esa es la diferencia real entre los dos primeros niveles. No es cuánto cuidas la spec. Es si la alineación depende de tu voluntad o de un check que falla el build.

    Spec-as-source: la spec es el código

    Definición del paper: la especificación es el único artefacto que los humanos editan directamente. El código se genera enteramente a partir de la spec.

    La regla operativa que da el paper es tajante: si quieres cambiar la funcionalidad, cambias la spec y regeneras. Nunca editas el código generado directamente.

    El drift desaparece. No se gestiona, no se detecta: no puede existir. Como el código se regenera en lugar de editarse a mano, spec y código están siempre alineados por construcción.

    Suena a futuro lejano. No lo es, y esto es lo que más me sorprendió del paper.

    Spec-as-source ya existe. Y una parte ya la haces

    Hay una idea instalada de que spec-as-source es hacia dónde vamos cuando los LLM sean lo bastante buenos.

    Falso. El paper lo desmonta con una frase: spec-as-source ya es práctica estándar en dominios con generación de código bien definida, y pone dos ejemplos. Uno es generar código embebido certificado desde modelos de Simulink. En la capa de control, el ingeniero rara vez escribe a mano el C que acaba en la ECU: escribe el modelo, y el generador produce el C.

    El otro ejemplo del paper es generar los stubs de servidor desde un openapi.yaml.

    Eso también es spec-as-source. Y llevas años haciéndolo sin llamarlo así: editas el contrato, regeneras, nunca tocas a mano lo generado. Es exactamente la regla del nivel tres.

    La diferencia es qué generas. Ahí generas el andamio. Nadie ha certificado un generador para la lógica de negocio.

    Entonces, ¿por qué no puedes hacer lo mismo con la lógica de tu app de Next.js?

    Porque, según el paper, spec-as-source solo es práctico hoy en dominios donde esa confianza está establecida. El paper no entra en por qué, pero la respuesta no está en el modelo: está en el toolchain. Generadores cualificados bajo norma, trazabilidad auditable y décadas de proceso detrás.

    Tu lógica de negocio no tiene eso. No porque la IA no dé la talla, sino porque no hay un organismo que responda cuando el código generado la líe en producción.

    Así que spec-as-source completo no es tu nivel hoy si haces web. Y no pasa nada. Perseguirlo con las herramientas actuales es la forma más rápida de acabar con el peor de los dos mundos: código generado que nadie entiende y una spec que tampoco es la fuente real de verdad.

    Qué cuesta subir de spec-first a spec-anchored

    Este es el salto que sí te interesa. Y es más barato de lo que parece, porque no va de escribir más documentación. Va de cerrar el bucle.

    El paper describe un flujo de cuatro fases: Specify → Plan → Implement → Validate.

    La mayoría hacemos tres. Especificamos, planificamos, implementamos, y en cuanto la feature funciona nos vamos a la siguiente. Validate se queda sin hacer. Y para mí, Validate es la fase que convierte spec-first en spec-anchored.

    En un proyecto normal de TypeScript, el salto son tres movimientos concretos.

    Uno: los criterios de aceptación de la spec dejan de ser prosa y pasan a ser tests. Cada comportamiento descrito en la spec tiene un test que lo verifica. Si la spec dice que un usuario sin permisos recibe un 403, hay un test que lo comprueba. Si no puedes escribir ese test, tu spec no era verificable — que es uno de los motivos por los que una spec falla con un agente de IA aunque esté impecablemente redactada.

    Dos: los contratos se validan contra la implementación. El paper lista aquí las herramientas por categoría: OpenAPI y Swagger, GraphQL SDL o Protocol Buffers para las specs de API, y Pact o Specmatic para contract testing. Tu openapi.yaml deja de ser documentación y pasa a ser el árbitro. Si el backend devuelve un campo que el contrato no declara, falla.

    Tres: eso corre en CI y rompe el build.

    # .github/workflows/ci.yml
    on: [push, pull_request]
    
    jobs:
      spec-alignment:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v5
          - run: npm ci
          - run: npm run test:contract     # implementación vs openapi.yaml
          - run: npm run test:acceptance   # escenarios derivados de la spec
    

    Ese bloque es la frontera entre los dos niveles. El día que alguien añade un endpoint sin tocar el contrato, el build se pone rojo antes de que llegue a review. La alineación deja de depender de que te acuerdes.

    Sobre el retorno de esto, el paper documenta un caso de estudio de microservicios API-first con OpenAPI y Specmatic con una reducción del 75% en el tiempo de ciclo de integración. Es un caso concreto del paper, no una media del sector, y conviene leerlo como lo que es: una señal de dónde está el valor, no una promesa.

    La parte incómoda es que este salto se apoya en tener una cultura de testing decente. Si tu suite de tests es frágil, spec-anchored no te va a salvar: vas a tener dos cosas rotas en vez de una. Arregla primero los tests — y si tu stack es Angular, esa base la trabajo entera con Jest y Testing Library en el curso de Testing en Angular, que es la misma disciplina en cualquier proyecto de TypeScript.

    El fallo que sobrevive a todos los niveles

    Hay una trampa que no se arregla subiendo de nivel, y el paper la nombra sin anestesia: los tests de spec que pasan no garantizan software correcto si las specs están mal.

    Falsa confianza. Para mí es el fallo más caro de los cuatro que lista el paper —junto a la sobre-especificación, la podredumbre de la spec y convertir las specs en burocracia— porque los otros tres se notan y este no.

    Tienes el CI verde, el contrato validado, los escenarios BDD pasando. Y estás construyendo con enorme rigor exactamente lo que el negocio no pidió.

    Por eso el paper reformula el rol del developer: pasamos de programar a mano a orquestar especificaciones, revisar salidas de IA y centrarnos en el diseño de alto nivel. Si tu spec es mala, subir de nivel solo automatiza el error y le pone un sello de calidad encima.

    La regla de oro del Spec-Driven Development: usa el mínimo rigor

    El paper cierra con un marco de decisión que merece la pena tener a mano. SDD aporta valor cuando hay asistencia de IA de por medio, requisitos complejos, sistemas de vida larga, varios mantenedores, generación de código viable o integración complicada. Y hay que saltárselo en prototipos desechables, trabajo en solitario de vida corta, código exploratorio o CRUD simple con requisitos evidentes.

    Que es básicamente lo que ya defendí en su día al hablar de cuándo no usar Spec-Driven Development, y me alegra ver que el paper llega a la misma conclusión.

    Porque el principio rector que se lleva el paper, y el que yo me he apuntado, es este:

    Usa el mínimo nivel de rigor de especificación que elimine la ambigüedad en tu contexto.

    Subir de nivel no es mejor. Es más caro. Spec-anchored en un script que vas a borrar en dos semanas no es madurez profesional, es ceremonia. Y spec-first en la plataforma que factura no es agilidad, es deuda con fecha de vencimiento.

    Lo que puedes hacer hoy, en diez minutos: coge tu proyecto más importante y aplícale el test de los 30 segundos. Borra mentalmente la carpeta specs/. Si no se rompe nada y ese proyecto va a vivir más de seis meses con más de una persona tocándolo, ya sabes cuál es tu siguiente PR. No es escribir más spec. Es añadir el check que la vuelve obligatoria.

    Si quieres el método completo —cómo redactar specs que un agente ejecuta sin inventarse la mitad y cómo mantenerlas vivas sin que se conviertan en burocracia— lo desarrollo entero en el libro de Spec-Driven Development. Y en Dominicode Labs tienes los proyectos donde esto está montado tal cual lo uso en producción, con el CI incluido.

    Preguntas frecuentes

    ¿Cuáles son los tres niveles de Spec-Driven Development?

    Spec-first, spec-anchored y spec-as-source. En spec-first la spec guía la implementación inicial y después puede quedar obsoleta. En spec-anchored la spec se mantiene junto al código durante todo el ciclo de vida y hay tests que verifican la alineación. En spec-as-source la spec es el único artefacto que edita un humano y el código se genera entero a partir de ella. Los definió Deepak Babu Piskala en el preprint arXiv:2602.00180.

    ¿Spec-first significa que lo estoy haciendo mal?

    No. Spec-first es un nivel legítimo y el paper lo recomienda explícitamente para prototipos, features de usar y tirar y desarrollo inicial con asistentes de IA. El problema aparece cuando aplicas spec-first a un sistema de vida larga y asumes garantías de trazabilidad que ese nivel no te da.

    ¿Cómo sé si mi spec está viva o solo bien escrita?

    Comprueba si algo del pipeline depende de ella. Si puedes borrar la spec y el build sigue verde, la spec es documentación. Una spec viva rompe algo cuando desaparece o cuando el código se desvía de ella, porque hay tests o validaciones de contrato que la usan como referencia.

    ¿Necesito Cucumber o BDD para ser spec-anchored?

    No obligatoriamente. El paper menciona los frameworks BDD (Cucumber, SpecFlow, Behave) como la forma habitual de que los escenarios se conviertan en tests automáticos, pero lo que define el nivel es que exista una verificación automática de la alineación, no la herramienta concreta. Con contract testing sobre OpenAPI usando Pact o Specmatic ya cumples el requisito.

    ¿Spec-as-source llegará algún día al desarrollo web?

    En parte ya llegó: generar los stubs de servidor desde un openapi.yaml es el ejemplo de spec-as-source que el propio paper pone, y es desarrollo web. Lo que no ha llegado es la lógica de negocio, y el cuello de botella no es la capacidad del modelo sino la confianza en el generador. En automoción y embebidos spec-as-source ya es práctica estándar desde hace años con Simulink o SCADE, y una de las razones es que esos generadores están cualificados bajo norma y auditados.

    Si mis tests de spec pasan, ¿está el software correcto?

    No. El paper lo advierte de forma directa: que los tests de spec pasen no garantiza que el software sea correcto si las propias specs son incorrectas. Verificar que cumples la spec y validar que la spec era la adecuada son dos problemas distintos, y el segundo sigue siendo humano.

    ¿Merece la pena spec-anchored si trabajo solo?

    Depende de la vida del proyecto, no del tamaño del equipo. El paper desaconseja SDD en trabajo en solitario de vida corta, pero si eres solo tú manteniendo algo durante años, el "otro mantenedor" eres tú dentro de ocho meses sin recordar nada. Ahí el contrato en CI te protege igual que protegería a un equipo.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Por qué Spec-Driven Development (SDD) triplica tu velocidad cuando programas con agentes de IA

    Por qué Spec-Driven Development (SDD) triplica tu velocidad cuando programas con agentes de IA

    Hace unas semanas estaba viendo trabajar a un desarrollador senior con bastante experiencia. Usaba una de las mejores herramientas de IA del mercado.

    Su flujo era este: escribía un prompt en el chat ("Agrégame la autenticación con OAuth y guarda el token en cookies HTTP-only"), la IA generaba 150 líneas de código, el código fallaba, le volvía a pedir que corrigiera el error, la IA cambiaba tres archivos sin avisar, se rompía el tipo de una interfaz… y de repente llevaba dos horas haciendo el famoso "prompt ping-pong".

    Tenía la sensación de ir rapidísimo porque la IA escribía texto a toda velocidad. Pero al final de la jornada, la mitad de su tiempo lo había pasado arreglando las suposiciones que la IA había tenido que inventar porque nadie se las definía.

    El problema no era la IA. El problema es que estaba intentando construir una casa pidiéndole al albañil que pusiera ladrillos sin enseñarle los planos. Aquí es donde Spec-Driven Development (SDD) transforma la forma en que los desarrolladores senior trabajan con los agentes de IA.

    El espejismo del "Vibe Coding" sin rumbo

    Nos han vendido que programar con IA consiste en hablarle en lenguaje natural como si fuera un colega y dejar que el LLM deduzca todo lo demás.

    Para un script de 20 líneas o un prototipo que vas a tirar mañana, funciona. Para software en producción con arquitecturas reales, es una trampa.

    Cuando no defines las reglas del juego antes de pedir código, obligas al agente de IA a tomar decenas de decisiones implícitas:

    • ¿Qué nombres le da a las variables y modelos?
    • ¿Cómo maneja los casos de borde y errores?
    • ¿Qué contrato sigue la API?
    • ¿Qué dependencias o utilidades existentes en el proyecto debe reutilizar?

    Si el agente adivina mal una sola de esas cosas, el código generado es basura técnica que tendrás que mantener tú. Como explicamos en nuestro artículo sobre por qué tu spec falla con un agente de IA, la falta de claridad en las restricciones es la causa número uno de código roto.

    ¿Qué es Spec-Driven Development (SDD)?

    Spec-Driven Development no es burocracia ni escribir documentación de 50 páginas que nadie lee.

    SDD consiste en invertir el flujo de trabajo: en lugar de usar la IA para que redacte código directamente desde tu cabeza, utilizas la IA para definir una especificación estructurada y verificable ANTES de escribir la primera línea de código.

    En nuestro workflow de producción, una especificación SDD se divide en tres piezas muy concretas:

    1. spec.md (La Especificación Funcional y Técnica)

    Define el QUÉ y el POR QUÉ.

    • Contexto del problema y objetivo.
    • Requisitos funcionales explícitos.
    • Contratos de datos, tipos e interfaces.
    • Reglas de negocio y lo que NO debe hacer el sistema.

    2. plan.md (La Arquitectura e Impacto)

    Define el CÓMO.

    • Qué archivos se modifican, cuáles se crean y cuáles se eliminan.
    • Estrategia de testing y verificación.
    • Modificaciones en dependencias o firmas de API.

    3. tasks.md (El Plan de Ejecución)

    Define el ORDEN.

    • Lista de tareas atómicas e independientes que el agente de IA puede ejecutar paso a paso sin perder contexto ni alucinar.

    Eso sí, ten en cuenta que no siempre necesitas cargar con toda la estructura: en nuestra guía sobre cuándo NO usar Spec-Driven Development detallamos los escenarios donde un enfoque más directo resulta más eficiente.

    El cambio mental: De programador a Director de Arquitectura

    Mira lo que ocurre cuando le das a un agente (como Claude Code, AGY o Cursor) una especificación bien acotada:

    # Spec: Interceptor de Telemetría HTTP
    ## Requisitos
    - Interceptar todas las peticiones salientes HttpClient.
    - Añadir el header X-Correlation-ID usando un UUID v4 si no existe previamente.
    - Si la petición responde con status 401, reintentar una sola vez tras renovar el token vía AuthService.refreshToken().
    - NO interceptar peticiones hacia /api/v1/auth/login.
    
    ## Contrato
    - Firma de error devuelta: ApiErrorResponse { code: string; message: string; timestamp: number }.
    

    Cuando un agente lee este archivo antes de tocar el código:

    1. El contexto entra limpio: El LLM no necesita adivinar el nombre del header ni la estrategia de reintento.
    2. Las respuestas son deterministas: El código generado encaja al primer intento con la arquitectura de tu aplicación.
    3. El tiempo de revisión tiende a cero: En lugar de leer 300 líneas de diff intentando adivinar qué pretendía hacer la IA, solo verificas que el código cumple los puntos de la spec.

    Cómo empezar con SDD hoy mismo

    No necesitas instalar un framework complejo ni cambiar la estructura de tu empresa.

    La próxima vez que vayas a pedirle una funcionalidad a tu agente de IA, haz esto:

    1. Escribe un archivo .md rápido en tu proyecto describiendo qué quieres lograr, qué archivos se verán afectados y cuáles son los tipos/interfaces involucrados.
    2. Pásale la spec al agente y pídele: "Revisa esta especificación. Identifica ambigüedades o contradicciones antes de proponer cambios".
    3. Una vez alineados en la especificación, pídele que genere la solución siguiendo las tareas definidas.

    Te aseguro una cosa: escribir esa spec te llevará 4 minutos. Te ahorrará 45 minutos de depuración descontrolada.

    Programar rápido con IA no consiste en teclear prompts más deprisa. Consiste en pensar con claridad antes de pedir el código.


    Si quieres llevar tus habilidades al siguiente nivel, explora los Cursos de Dominicode donde profundizamos en arquitecturas modernas y herramientas de desarrollo. Además, en Dominicode Labs acompañamos a developers a construir productos reales y workflows autónomos asistidos por IA.

    Preguntas frecuentes

    ¿SDD reemplaza a TDD (Test-Driven Development)?

    No, se complementan. SDD define el contrato y las expectativas de alto nivel antes de construir, mientras que TDD asegura la corrección del código a nivel unitario durante la implementación.

    ¿Cuánto tiempo lleva escribir una especificación SDD?

    Para una tarea típica de feature, redactar una spec básica toma entre 3 y 8 minutos. Ese pequeño esfuerzo inicial ahorra habitualmente horas de refactorización y depuración.

    ¿Qué herramientas son ideales para trabajar con Spec-Driven Development?

    SDD es agnóstico a la herramienta, pero brilla especialmente con agentes CLI como Claude Code y AGY, o entornos con contexto profundo como Cursor y Windsurf.

    ¿Es necesario usar SDD para correcciones de bugs pequeñas?

    Para bugs triviales o cambios de una sola línea no es necesario crear una spec completa. SDD es más valioso en tareas que involucran múltiples archivos, lógica de negocio o contratos de interfaz.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Marcas de agua en Claude Code: ¿pueden detectar tu código?

    Marcas de agua en Claude Code: ¿pueden detectar tu código?

    Un compañero me mandó el titular por Telegram a las siete de la mañana. Debajo, una sola línea: "¿Entonces pueden saber que este commit lo escribí con Claude Code?".

    Es la pregunta correcta. Y la respuesta corta es incómoda: hoy nadie te lo puede demostrar, porque el detector público de las marcas de agua de Claude todavía no existe.

    La respuesta larga es más interesante. Va de por qué estas marcas funcionan razonablemente bien sobre prosa y se deshacen casi solas dentro de un repositorio de código.

    La familia de marcas de agua más documentada en la literatura no es un carácter oculto ni un metadato: es un sesgo estadístico introducido durante la generación, en la elección misma de las palabras, que deja una firma detectable sin alterar el significado. Anthropic no ha confirmado que la suya funcione así. Solo dice que va "tejida dentro del propio texto".

    He leído la documentación entera. Esto es lo que dice, y lo que no.

    Documentación de Anthropic actualizada el 11 de agosto de 2026. Última revisión de este post: 12 de agosto de 2026.


    Qué ha anunciado Anthropic exactamente

    Cuatro hechos, sin adornos.

    1. Anthropic ha firmado el Código de Buenas Prácticas del Artículo 50(2) del Reglamento Europeo de IA sobre transparencia del contenido generado por IA. Esto no es marketing: es cumplimiento normativo.
    2. Los modelos Claude lanzados a partir del 2 de agosto de 2026 salen con marcado machine-readable desde el primer día. Para los modelos anteriores hay un periodo transitorio y Anthropic dice que está trabajando en incorporarlo.
    3. El alcance cubre Claude Platform (la API), Claude, Claude Code, Claude Cowork y Claude Tag, además de Claude servido desde AWS, Google Cloud y Microsoft Foundry. Se aplica en todo el mundo, no solo en la Unión Europea. Con una salvedad que conviene retener para más adelante: la marca en el texto sí viaja por esas tres nubes, pero los metadatos de procedencia firmados "puede que no estén soportados en todas las plataformas, según las funcionalidades que ofrezca cada una".
    4. La documentación no contempla ningún opt-out: el marcado se aplica a la salida de los modelos soportados, también cuando consumes la API.

    Que Claude Code aparezca escrito con todas las letras en esa lista es lo que hace que este post exista.

    Sobre el mecanismo, la documentación de Anthropic dice esto y nada más:

    "Teje una marca de agua imperceptible directamente en el propio texto. No la verás, y no cambia el significado, la calidad ni la legibilidad de la respuesta de Claude."
    ("…it weaves an imperceptible watermark directly into the text itself. You won't see it, and it doesn't change the meaning, quality, or readability of Claude's response.")

    Punto. No publican el algoritmo.


    Cómo se mete una marca de agua dentro de un texto

    La técnica estándar sesga la elección de tokens: en cada paso el modelo parte el vocabulario en una lista verde y una roja usando un hash secreto, y empuja suavemente la generación hacia la verde. El texto sigue siendo natural, pero contiene más tokens verdes de los que el azar explicaría.

    Aclaración previa: Anthropic no ha publicado su algoritmo. Lo que viene ahora es cómo funciona la familia de técnicas conocida en la literatura académica —sobre todo el trabajo de Kirchenbauer et al., "A Watermark for Large Language Models" (2023)—, no una descripción de lo que hace Claude por dentro.

    Lo explico porque es didáctico y porque es la familia plausible. No porque sea un dato confirmado.

    Un modelo de lenguaje no escribe palabras: escribe tokens. En cada paso genera un vector de logits, una puntuación para cada token del vocabulario, y de ahí sale la distribución de la que se muestrea el siguiente. Si nunca has visto por dentro cómo se trocea el texto, en Tokens en español: por qué cuestan un 26 % más que en inglés lo explico con ejemplos reales.

    La técnica clásica hace esto:

    1. Toma los últimos tokens generados y calcula un hash con una clave secreta.
    2. Usa ese hash como semilla para partir el vocabulario en dos: una lista verde y una lista roja.
    3. Suma un pequeño sesgo a los logits de la lista verde antes de muestrear.
    4. Repite en cada token.

    El texto resultante es perfectamente natural. Pero contiene muchos más tokens "verdes" de los que el azar justificaría. Quien tenga la clave recalcula las listas y saca un valor estadístico de confianza.

    La gracia del método es que el detector no necesita el modelo. Solo la clave y suficiente texto.

    Ahí está la palabra que lo condiciona todo: suficiente.


    Marca de agua no es lo mismo que detector de IA

    Un detector de IA adivina a partir del estilo; un detector de marca de agua busca una firma concreta que el propio modelo insertó. Son dos tecnologías distintas, con tasas de error distintas, y confundirlas es el error que más circula esta semana.

    Detector de IA Detector de watermark
    Analiza estilo Sí No
    Conoce la firma No Sí
    Necesita clave No Posiblemente
    Es probabilístico Sí Sí
    Identifica proveedor Difícil Potencialmente

    Un detector de IA clásico —los que llevan años suspendiendo a estudiantes por escribir demasiado bien— hace estadística sobre el estilo: perplejidad, longitud de frase, variedad léxica. Adivina. Un detector de watermark no adivina: busca una firma concreta que sabe que está ahí.

    Anthropic dice que "está trabajando para permitir que usuarios y terceros detecten las marcas de agua incrustadas de Claude y los metadatos de procedencia" y que publicará los detalles más adelante. Traducido: hoy no hay detector público de la marca de agua de Claude, ni fecha.

    De ahí sale la frase que más falta hace repetir esta semana: cualquier web que hoy te diga "este texto contiene el watermark de Claude" sin acceso al mecanismo de verificación de Anthropic, está vendiendo humo. Sin ese mecanismo no hay verificación posible. Hay marketing.


    El problema de la baja entropía cuando escribes código

    Una marca de agua estadística es más débil sobre código que sobre prosa porque el código tiene poca entropía: en cada punto hay muy pocas continuaciones válidas y casi ningún margen para elegir un token en lugar de otro equivalente.

    Y esto no me lo invento yo. Kirchenbauer et al. le dedican una sección entera del paper, titulada "A caveat: The difficulty of watermarking low-entropy sequences", y la abren así: "El texto de baja entropía crea dos problemas para el marcado. El primero: tanto humanos como máquinas producen terminaciones parecidas, si no idénticas, ante prompts de baja entropía, lo que hace imposible distinguir unas de otras."

    Lo que sí es inferencia mía es aplicárselo a Claude. Anthropic no ha publicado su algoritmo ni ninguna política específica sobre código.

    Una marca de agua estadística necesita libertad de elección. Si el modelo tiene veinte formas igual de válidas de continuar una frase, puede empujar hacia la lista verde sin que se note. En prosa esto sobra: "rápido" o "veloz", "por tanto" o "así que".

    El código no funciona así.

    Después de const user = await this.userService. hay dos o tres continuaciones razonables y el resto son errores de compilación. La entropía se hunde. El modelo no puede elegir un nombre de método "más verde" si el método se llama como se llama en la interfaz, y no puede reordenar los argumentos porque la firma es la que es.

    Cuanto más determinista es la salida, menos sitio hay donde esconder señal. Y el código es el texto más determinista que produce un modelo. Es la misma naturaleza probabilística que explico en por qué la IA se inventa cosas: ese margen de maniobra permite tanto la alucinación como la marca de agua. En código, el margen se estrecha.

    Añade que la mayoría de los diffs que revisas en un PR son de veinte o treinta líneas. Anthropic no da ningún umbral, pero sí reconoce el límite: un pasaje muy corto deja "demasiado poco texto para una señal fiable".

    El paper de Kirchenbauer sí da números. En sus experimentos detectan el 98,4 % de las generaciones al umbral z=4, que se alcanza a los 128 tokens. Y avisan, en la misma sección: "Las secuencias de alta entropía se detectan con relativamente pocos tokens, mientras que las de baja entropía requieren más tokens para ser detectadas."

    Junta las dos frases y verás por qué el número engaña. Ciento veintiocho tokens son del orden de diez o quince líneas de TypeScript, bastante menos que un commit cualquiera. Parece buena noticia para quien quiera detectarte. No lo es: ese 98,4 % está medido sobre prosa periodística, y el código es exactamente el material de baja entropía que, según los propios autores, necesita bastantes más tokens. Cuántos más, no lo dice nadie. Echa tú la cuenta con el tamaño de tus commits.


    Por qué tu flujo de trabajo real lava la marca

    Formatear, refactorizar, renombrar y revisar código altera la secuencia de tokens, y eso es lo que deshace una marca estadística sin que nadie se lo proponga.

    Separemos las dos mitades del argumento, porque solo una está documentada. La documentada: Anthropic dice que la marca puede dejar de detectarse si el texto "ha sido editado en profundidad, parafraseado, traducido o mezclado con otra escritura" ("heavily edited, paraphrased, translated, or mixed into other writing"). La mía: que tu flujo de trabajo normal, el de cualquier martes, cuenta como editar en profundidad.

    Conviene citar también la otra mitad, porque Anthropic la dice y casi nadie la está recogiendo: la marca "viaja con el texto cuando se copia y pega en otro sitio, y puede sobrevivir a algunas ediciones". Es cierto y no contradice lo anterior. Copiar y pegar no toca la secuencia de tokens: la marca sigue ahí intacta. Lo que la rompe es cambiar el orden de esos tokens, y eso es precisamente lo que hacen el formateador, la extracción de método y el renombrado.

    Lee las dos frases otra vez y piensa en cómo trabajas de verdad con Claude Code a diario.

    Spec-Driven Development reduce la libertad del modelo

    Cuando trabajas con una spec detallada —nombres de tipos, contratos, estructura de carpetas, criterios de aceptación— no le pides al modelo que invente. Le pides que transcriba una decisión que ya tomaste tú.

    Si la marca funciona como creo —y esto sigue siendo inferencia mía—, cuanto más rigurosa sea la spec, menos libertad probabilística le queda al modelo y menos espacio hay donde incrustar señal. Un efecto secundario curioso de una metodología que adopté por razones completamente distintas, y que tienes desarrollada entera en el libro de Spec-Driven Development.

    El efecto Prettier

    Esto es más brutal todavía, y pasa cada día sin que lo pienses.

    Guardas el archivo y el formateador reparte los saltos de línea a su manera. Extraes un método. Renombras data por invoiceLines porque el nombre no decía nada. Mueves el bloque a otro archivo. El linter reordena los imports. Pasa por code review y alguien cambia tres cosas.

    Cada una de esas operaciones altera la secuencia de tokens. Y cualquier marca estadística de la familia que describí arriba depende, literalmente, del orden exacto de esos tokens. Que la de Claude funcione así es inferencia mía. Que editar en profundidad pueda dejarla indetectable lo dice Anthropic.

    No es que estés intentando borrar nada. Es que hacer bien tu trabajo la borra. Auditar y refactorizar lo que genera el asistente en lugar de aceptarlo tal cual es justo el flujo que enseño en Construye con IA, y resulta que además tiene este efecto colateral.


    Lo que sí aguanta: C2PA en los archivos que genera Claude

    Hay un caso donde la marca sí resiste: los archivos. Cuando Claude genera un .svg, .png o .jpg entra un segundo mecanismo: incrusta metadatos de procedencia firmados criptográficamente con el estándar C2PA, de la Coalition for Content Provenance and Authenticity. Anthropic no dice que esto sustituya a la marca del texto; dice que esos formatos llevan además procedencia.

    Otra liga. Una firma criptográfica no es probabilística: o valida o no valida. Y permite detectar si el archivo fue manipulado después.

    Y aquí está el contraste que más importa: la marca de agua del texto no la puede verificar nadie fuera de Anthropic, pero el C2PA sí se verifica ya hoy con herramientas públicas como c2patool o contentcredentials.org. Uno es una promesa; el otro funciona esta tarde.

    Un detalle técnico que conviene fijar: un .svg es un archivo de texto, XML, no un binario. Los metadatos viven dentro del propio documento. Y aplica a los archivos que Claude genera, no a los que ya tienes en el proyecto.

    O sea: si le pides a tu agente los iconos SVG de la aplicación y los commiteas tal cual, esos archivos sí llevan procedencia verificable dentro del repo. Puedes comprobarlo tú mismo:

    c2patool icono-generado.svg
    

    Durarán hasta que alguien los pase por un optimizador, los convierta de formato o los vuelva a guardar: Anthropic avisa de que la conversión de formato, el re-guardado y las capturas de pantalla eliminan los metadatos.

    Y hay una limitación más, la que dejé apuntada al principio: los metadatos firmados "puede que no estén soportados en todas las plataformas". Si consumes Claude a través de AWS, Google Cloud o Microsoft Foundry, la marca del texto viaja igual, pero la procedencia de los archivos depende de lo que ofrezca cada plataforma. Anthropic lo incluye entre las causas por las que un contenido marcado puede no dar señal: haberse producido "a través de una plataforma, funcionalidad o tipo de archivo donde ese tipo de marcado no estaba soportado".

    Robusto, pero no indestructible.


    El falso positivo: detectar la marca no prueba autoría

    Todo lo anterior va de falsos negativos: la marca está y se pierde. Pero hay un problema en la dirección contraria, y lo reconoce la propia Anthropic.

    Detectar una marca de Claude te dice que el contenido "puede haber sido procesado por Claude" ("may have been processed by Claude"). No que Claude lo escribiera. La documentación lo desarrolla sin rodeos: "Claude puede no ser el autor original. La gente usa Claude a menudo para corregir, traducir, resumir o convertir archivos."

    Léelo despacio, porque cambia la conversación entera.

    Si coges una función que escribiste tú y le pides a Claude que la refactorice, que le añada tipos o que te traduzca los comentarios al inglés, la salida sale marcada igual. La marca prueba paso por el modelo, no autoría del modelo.

    Y el reverso también está escrito: "la ausencia de marca detectada no significa que el contenido no fuera generado o procesado por IA".

    O sea que la señal falla en las dos direcciones. Quien pretenda usar una detección como prueba de que no escribiste tú el código está leyendo mal la herramienta, y ahora tienes la frase del fabricante para decírselo.


    ¿Qué otras IAs marcan el contenido que generan?

    Anthropic no es la primera ni va sola. El Artículo 50(2) empuja a todo el sector en la misma dirección, pero cada uno ha llegado hasta un punto distinto.

    Proveedor Marca el texto Marca archivos ¿Verificable hoy por ti?
    Anthropic (Claude) Sí, desde agosto de 2026 Sí, C2PA en .svg, .png, .jpg Texto: no. Archivos: sí, C2PA
    Google (Gemini) Sí, SynthID-Text Sí, SynthID en imagen, audio y vídeo No: leer SynthID requiere la clave de Google
    OpenAI (ChatGPT) No Sí, C2PA en imágenes y SynthID en audio Solo lo que expone C2PA

    Google llegó antes: SynthID-Text lleva desplegado en Gemini desde 2024 y fue el primer marcado de texto en producción a escala. Firmó el mismo Código de Buenas Prácticas el 24 de julio de 2026, una semana antes de que el Artículo 50 fuera aplicable, y anunció acuerdos con Apple, ElevenLabs, Kakao, NVIDIA y OpenAI para que el marcado sea interoperable entre proveedores.

    Fíjate en la casilla que se repite: nadie tiene detector público de texto. Ni Anthropic ni Google. SynthID lleva dos años funcionando y sigue necesitando la clave privada de Google para leerse. Eso te dice más sobre el plazo real de Anthropic que cualquier promesa de documentación futura.

    Y el caso de OpenAI merece un párrafo, porque es el más honesto sobre los incentivos del negocio: tenía el marcado de texto construido y lo aparcó en septiembre de 2024, cuando una encuesta interna reveló que cerca del 30 % de los usuarios de ChatGPT lo usarían menos si supieran que marca lo que escribe. Marca imágenes y audio, donde nadie protesta. Texto no.


    Entonces, ¿debería preocuparte?

    Respuesta corta: no, si escribes software y auditas lo que genera el asistente. Sí, si tu empresa firma contratos con cláusulas sobre uso de IA y nadie las ha leído.

    La iniciativa es buena ingeniería y buena regulación. La web abierta se está llenando de texto sintético que se hace pasar por humano, y marcarlo en origen es mejor que dejarlo en manos de detectores que funcionan por corazonadas estilísticas.

    Para quien escribe software, el código sigue siendo código.

    Tu repositorio no es un canal de distribución de texto sintético. Es un artefacto de ingeniería que pasa por specs, revisión, formateo, refactor y tests. Mientras controles la arquitectura y audites lo que genera el asistente, es poco probable que una marca estadística sobreviva a ese recorrido. Y mientras no haya detector público, ni tú ni nadie puede comprobarlo.

    Lo único que te recomiendo hacer hoy: si tu empresa firma contratos con cláusulas sobre uso de IA, sube el tema tú antes de que lo suba un cliente. No para justificarte —usar Claude Code no es hacer trampas—, sino para tener una política escrita en lugar de una improvisación en una llamada incómoda.

    Si quieres seguir estas cosas con gente que las aplica en producción y no solo lee titulares, en Dominicode Labs es de lo que hablamos cada semana.


    Preguntas frecuentes

    ¿Puede alguien saber hoy si usé Claude para escribir este código?

    No. Anthropic no ha publicado ni el algoritmo ni un detector público, y no ha dado fecha. Dice que trabaja para que usuarios y terceros puedan detectar las marcas, y que compartirá los detalles en documentación técnica futura. Hasta entonces, cualquier herramienta que afirme lo contrario no puede demostrarlo.

    ¿La marca de agua afecta a la calidad del código que genera Claude?

    Anthropic afirma que no cambia el significado, la calidad ni la legibilidad. En prosa es creíble: el sesgo se reparte entre alternativas equivalentes. En código las alternativas equivalentes escasean, así que —y esto es deducción mía, no dato publicado— cualquier esquema de marcado tendría mucho menos margen de actuación. No hay motivo para esperar peor código por esto.

    ¿Puedo desactivar la marca de agua?

    La documentación de Anthropic no menciona ninguna opción para desactivarlo, tampoco para quien usa la API. Se aplica a Claude Platform, Claude, Claude Code, Claude Cowork y Claude Tag, incluido Claude servido a través de AWS, Google Cloud y Microsoft Foundry, y rige en todo el mundo.

    ¿La marca de agua sobrevive a copiar y pegar el código?

    Sí. Anthropic dice que la marca "viaja con el texto cuando se copia y pega en otro sitio, y puede sobrevivir a algunas ediciones". Copiar y pegar no altera la secuencia de tokens, así que no hay motivo para que se pierda. Lo que sí puede romperla, según la propia documentación, es editar en profundidad, parafrasear, traducir o mezclar el texto con otra escritura.

    ¿Cómo compruebo si un archivo generado por Claude lleva metadatos C2PA?

    Con c2patool desde la terminal (c2patool archivo.svg) o subiendo el archivo a contentcredentials.org. Esto es lo único verificable hoy sin depender de Anthropic, y solo aplica a archivos .svg, .png y .jpg generados por Claude. Los metadatos desaparecen si conviertes el formato, vuelves a guardar el archivo o haces una captura de pantalla.

    ¿Afecta la marca de agua a quién es dueño del código que genera Claude?

    No. La marca es un mecanismo de transparencia sobre el origen del contenido, no un mecanismo de propiedad. La titularidad de lo que generas con Claude se rige por los términos de servicio de Anthropic y por el contrato que tengas con tu cliente o tu empresa, no por si el texto lleva firma estadística. Lo que sí conviene es que esa relación esté escrita antes de que alguien pregunte.

    ¿Los detectores de IA como GPTZero o Turnitin detectan la marca de agua de Claude?

    No. Son mecanismos distintos. Un detector convencional analiza el estilo y estima una probabilidad; no conoce ninguna firma y se equivoca a menudo en las dos direcciones. Un detector de watermark busca una señal concreta que sabe cómo se incrustó. Que un detector clásico marque tu texto como generado por IA no significa que haya encontrado la marca de Anthropic, porque no puede.

    Si detectan la marca, ¿significa que el código lo escribió Claude?

    No, y lo dice Anthropic: detectar una marca de Claude indica que el contenido "puede haber sido procesado por Claude", no que Claude lo escribiera. Si le pasas tu propio código para que lo refactorice o te lo traduzca, la salida sale marcada igual. La marca prueba paso por el modelo, no autoría del modelo. Cualquiera que use una detección como prueba de que no escribiste tú el código está leyendo mal la señal.

    ¿Me afecta si no estoy en la Unión Europea?

    Sí. El marcado nace del Código de Buenas Prácticas del Artículo 50(2) del Reglamento Europeo de IA, pero Anthropic lo aplica globalmente. Dónde esté tu empresa no cambia nada.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Por qué tu spec falla con un agente de IA: 7 fallos y su arreglo

    Por qué tu spec falla con un agente de IA: 7 fallos y su arreglo

    La spec tenía 900 palabras, títulos bien puestos, listas numeradas y hasta un diagrama. El agente la leyó entera y construyó otra cosa.

    El dev que me la pasó estaba convencido de que el problema era el modelo. Probó con otro. Mismo resultado.

    Le hice una sola pregunta: cuando el agente termine, ¿qué comando ejecutas para saber si lo ha hecho bien?

    Silencio. No había ninguno.

    Ese silencio es el diagnóstico completo. La mayoría de las specs que fallan —también las de quien ya aplica Spec-Driven Development a diario— no fallan por estar mal escritas. Fallan por no ser verificables. Y una spec que no se puede comprobar no es una especificación: es una carta de intenciones. Un agente no ejecuta intenciones.

    El SDD no consiste en redactar un documento bonito antes de programar — de eso hablé cuando expliqué por qué el Spec-Driven Development evita el caos. Consiste en escribir un contrato que una máquina pueda dar por cumplido o por incumplido, sin que tú tengas que opinar.

    Esto no es otro tutorial de redacción. Para la estructura desde cero ya tienes la anatomía de una spec para Claude Code. Esto es el diagnóstico de la spec que ya escribiste y no funcionó.

    Siete fallos, ordenados por lo que más veo. Los cinco primeros los detectas leyendo el documento. Los dos últimos, no.

    Busca tu síntoma: por qué tu spec falla con un agente de IA

    Lo que ves cuando el agente termina El fallo en la spec El arreglo
    Dice "está hecho" y no sabes si está hecho Criterios de éxito no comprobables Un comando debajo de cada criterio
    Hace las cosas como las hace todo el mundo, no como tu repo Ambigüedad sin marcar Señala el fichero que manda
    Toca ficheros que nadie le pidió No hay límites Sección "Fuera de alcance"
    Ignora la mitad de tus instrucciones técnicas Mezcla el qué con el cómo Cierra el qué, deja el cómo abierto
    catch vacíos y fallos que devuelven 200 Solo describe el camino feliz Tabla de estados de error
    Empieza bien y se desmadra a la mitad La spec es demasiado grande Pártela por unidad verificable
    Cumple la spec, pero la spec ya no es verdad Spec desactualizada Vive en el repo o se borra

    Fallo 1: criterios de éxito que nadie puede comprobar

    Un criterio de éxito es comprobable cuando existe un comando que lo declara cumplido o incumplido sin que nadie opine. Este es el fallo padre: los otros seis son variaciones suyas.

    Mira esta spec. La he leído con distintos nombres decenas de veces:

    ## Feature: listado de productos
    
    Endpoint para listar el catálogo.
    Tiene que ser rápido y soportar filtros.
    La respuesta debe ser consistente con el resto de la API.
    Gestionar bien los errores.
    

    Cuatro frases. Tres deseos y un título. ¿Rápido comparado con qué? ¿Consistente con cuál de los catorce endpoints que ya tienes? ¿Gestionar bien es devolver un 400 o un 422?

    Ninguna de esas preguntas la puede responder el agente ejecutando algo. Así que las responde inventando, y tú te enteras después.

    Ahora la misma feature escrita para que se pueda comprobar:

    ## Feature: GET /products
    
    ### Criterios de aceptación
    1. `GET /products?limit=20` devuelve 200 con
       `{ items: Product[], nextCursor: string | null }`.
    2. Paginación por cursor sobre `created_at DESC, id DESC`.
       `GET /products?cursor=<nextCursor>` devuelve la página siguiente
       sin repetir ni saltarse elementos. Nada de offset/limit.
    3. `limit` acepta 1-100, por defecto 20.
       Fuera de rango devuelve 400 con `{ code: 'INVALID_LIMIT' }`.
    4. p95 por debajo de 200 ms con 10.000 productos en tabla.
    
    ### Cómo se verifica
    - `bun test test/products.e2e.ts` en verde (cubre los puntos 1 a 3).
    - `bun run bench:products` imprime el p95 y sale con código 1
      si supera los 200 ms.
    

    La diferencia no es la longitud. Es que la segunda tiene una sección Cómo se verifica.

    "Que sea rápido" es un deseo. "Que GET /products responda por debajo de 200 ms de p95 con 10.000 registros, y aquí está el comando que lo mide" es un criterio. El primero obliga a que alguien juzgue. El segundo se cierra solo.

    Regla corta: debajo de cada criterio, el comando que lo prueba. Si no puedes escribir el comando, no tienes un criterio, tienes una preferencia.

    Y cuando el criterio es ejecutable pasa lo interesante: puedes delegar el ciclo entero —escribe, ejecuta, lee el fallo, corrige— en lugar de revisar cada iteración a mano. Es el flujo diario que describí en cómo usar Claude Code a diario, y depende por completo de que exista ese comando.

    Fallo 2: la ambigüedad la rellena el modelo, no tú

    Todo hueco de la spec se rellena. Siempre. La pregunta no es si el agente va a improvisar, es con qué.

    Y improvisa con lo más común de su entrenamiento: la mediana de internet. Tu repo no es la mediana de internet.

    Si tu API pagina por cursor y la spec solo dice "con paginación", el agente escribe offset y limit, porque es el patrón que domina en el código público con el que se entrenó. Si tu proyecto devuelve Result en vez de lanzar, escribirá try/catch. Si tus tests usan Testing Library, te meterá un TestBed clásico.

    Ninguno de esos es un error del modelo. Son la respuesta estadísticamente correcta a una pregunta que no hiciste.

    Aquí está el matiz que casi nadie aplica: la spec no tiene que decirlo todo. Tiene que decir dónde no se puede improvisar.

    Y la forma más barata de decirlo no es describir tu patrón en tres párrafos. Es apuntar al código que ya lo hace:

    ### Referencias obligatorias
    - Paginación: copia el patrón de `src/orders/orders.controller.ts` (solo lectura).
      Si hay conflicto entre este documento y ese fichero, manda el fichero.
    - Errores: usa los helpers de `src/common/http-errors.ts`.
      Prohibido lanzar `Error` pelado.
    
    ### Libre elección
    - Nombres internos, orden de los métodos, dónde partes los helpers.
      No preguntes por esto.
    

    Ese último bloque parece de relleno y no lo es. Marcar lo que sí es libre evita el otro extremo: el agente que se para cada dos minutos a preguntar cómo llamar a una variable.

    Tu trabajo no es documentar el proyecto entero dentro de la spec. Es marcar las tres o cuatro fronteras donde una decisión razonable sería, en tu repo, la decisión equivocada.

    Fallo 3: no dice qué NO hacer

    Los desastres que he visto con agentes casi nunca vienen de lo que el agente no hizo. Vienen de lo que hizo de más.

    Le pides un endpoint y te reformatea 40 ficheros porque detectó que el estilo era inconsistente. Le pides un filtro y te instala una librería de query building. Le pides un fix y "de paso" refactoriza el módulo de auth, que estaba feo.

    Todo eso es técnicamente razonable. Ninguna spec lo prohibía.

    Los límites son parte del contrato, no una nota al margen:

    ### Fuera de alcance
    - No tocar `src/auth/**` ni `src/orders/**`.
    - No añadir dependencias. La paginación sale del query builder
      que ya está en `src/common/pagination.ts`.
    - No crear migraciones. Si hace falta un índice, lo propones
      en el PR y paras.
    - No cambiar la forma de respuesta de endpoints existentes.
    - No reformatear ficheros que no toque la feature.
    

    Cinco líneas. Te ahorran la revisión de un diff de 40 ficheros donde lo que importa está en tres. Es, por cierto, uno de los patrones que aparece una y otra vez en los errores comunes al adoptar Claude Code: falta de guardarraíles, no falta de capacidad.

    No es opinión mía: las buenas prácticas oficiales de Claude Code lo dicen con todas las letras — las specs más útiles "nombran los ficheros e interfaces implicados, declaran qué queda fuera de alcance, y terminan con un paso de verificación end-to-end que demuestra que la feature funciona". Los tres primeros fallos de esta lista son exactamente esas tres cosas, en negativo.

    Fallo 4: la spec que ya decide la implementación

    Este falla al revés que los anteriores. No peca de vaga, peca de mandona.

    Crea un `ProductsCacheInterceptor` en `src/products/interceptors/`.
    Usa un `Map<string, { data: Product[]; ts: number }>` en memoria.
    TTL de 60 s, limpieza con un `setInterval` cada 30 s.
    La clave del Map es `JSON.stringify(req.query)`.
    

    Eso no es una spec. Es pseudocódigo con saltos de línea.

    Y tiene un agujero que probablemente no has visto: JSON.stringify(req.query) genera claves distintas para ?limit=20&cursor=x y ?cursor=x&limit=20. Son la misma petición. El agente puede implementar ese documento al pie de la letra, perfectamente, y aun así pegarle dos veces a la base de datos.

    La versión que sí es un contrato:

    ### Criterio
    Dos peticiones con los mismos parámetros a `GET /products` en menos de 60 s
    golpean la base de datos una sola vez, independientemente
    del orden de los parámetros en la query string.
    
    ### Cómo se verifica
    `bun test test/products.cache.e2e.ts` — el test espía el
    repositorio y afirma que solo hubo una query.
    
    ### Restricciones
    Sin dependencias nuevas. Sin Redis: todavía no está en infra.
    

    Fíjate en la paradoja. La versión que no dice cómo implementarlo es más exigente que la que lo dictaba línea a línea. La primera se puede cumplir y estar mal. La segunda no se puede fingir.

    Además, cuando cierras el cómo, cierras también las soluciones mejores que la tuya. Y en cachés, colas y consultas, el agente propone alternativas buenas más a menudo de lo que resulta cómodo admitir.

    Tú decides el qué observable. Él decide el cómo. El test decide quién tiene razón.

    Fallo 5: la spec solo describe el camino feliz

    Abre tu última spec y cuenta cuántas líneas hablan de qué pasa cuando algo falla. Lo normal es cero.

    Aquí está la trampa: el agente no deja el manejo de errores sin hacer. Lo inventa. Y su versión inventada suele ser un catch que loguea y sigue, o un 200 con array vacío cuando la base de datos no responde. Un endpoint que miente en lugar de fallar.

    Cuatro filas arreglan esto:

    Caso Respuesta Qué se loguea
    cursor malformado 400 INVALID_CURSOR warn, sin volcar el cursor entero
    limit fuera de 1-100 400 INVALID_LIMIT nada
    Timeout de la base de datos (>2 s) 503 DB_TIMEOUT error, con query y duración
    Fila de producto sin precio se excluye del listado warn con el id

    La última fila separa una spec escrita por alguien que ha estado de guardia de una escrita de memoria. Los datos sucios existen, y si no decides tú qué hacer con ellos, decide el agente.

    Dos minutos de escritura. Es lo que hay entre un endpoint y un endpoint que puedes dejar sin mirar.

    Los dos fallos que no ves leyendo la spec

    Los cinco anteriores se detectan releyendo el documento. Estos dos solo aparecen cuando comparas la spec con el repo y con el tamaño del trabajo.

    Fallo 6: la spec es demasiado grande

    La unidad de una spec no es la feature, es el paso verificable. Si la sección "Cómo se verifica" no cabe en cinco líneas, no tienes una spec: tienes tres disfrazadas de una.

    El síntoma es inconfundible: el agente empieza bien y se desmadra a la mitad, porque cada decisión que toma amplía la superficie de las siguientes.

    Partir el trabajo en unidades que se cierran una a una es, literalmente, la mitad del método que enseño en Construye con IA. La otra mitad es no volver a abrir una unidad ya cerrada.

    Fallo 7: la spec está desactualizada

    La spec dice que el endpoint devuelve items, el código lleva tres semanas devolviendo data. El agente no tiene forma de saber cuál manda. Unas veces sigue al documento y otras al código, y ninguna de las dos es una elección tuya.

    La regla que uso: la spec vive en el repo, entra en el mismo PR que el código, y cuando se contradicen gana el código. Entonces actualizas la spec o la borras. Una spec muerta es peor que no tener spec, porque es contexto con autoridad que resulta ser mentira.

    El test de 30 segundos: ¿tu spec es verificable?

    Una spec es verificable si responde a tres preguntas por escrito. No hace falta reescribir nada para saberlo. Coge la que ibas a pasarle al agente y hazle estas tres:

    1. ¿Qué comando prueba que está terminada?
    2. ¿Qué ficheros no puede tocar?
    3. ¿Qué pasa exactamente cuando falla?

    Si las tres tienen respuesta escrita en el documento, la spec funciona. Si falta una, ya sabes dónde está el bug — y no está en el modelo.

    Empieza hoy por la primera. Coge tus criterios de aceptación y escribe debajo de cada uno el comando que lo demuestra. Los que se queden sin comando, o los conviertes en algo medible o los sacas de la spec, porque no van a pasar de deseo.

    Todo el sistema —el contrato verificable, los límites, cómo partir el trabajo y cómo mantener la spec viva junto al código— es lo que ordené en SDD: Spec-Driven Development. Si este post te ha señalado tres fallos en tu documento, ahí tienes el método completo para que no vuelvan.

    Y si prefieres verlo sobre proyectos reales, con specs de gente que las está usando en producción, es una de las conversaciones habituales en Dominicode Labs.

    Preguntas frecuentes

    ¿Cómo sé si mi spec es verificable?

    Una spec es verificable si cada criterio de aceptación tiene debajo un comando que devuelve verde o rojo sin que nadie opine. Un test, un benchmark, un script de validación, un curl con la respuesta esperada.

    La prueba rápida: pásale la spec a alguien que no conozca el proyecto y pídele que te diga si está hecha sin abrir el código. Si necesita preguntarte algo, el agente también lo habría necesitado, solo que él no pregunta.

    ¿Qué hago con los criterios que no se pueden medir con un comando?

    Los conviertes en algo observable o los sacas de la spec. "Que la UI sea intuitiva" no es un criterio, pero "que el flujo de compra se complete en tres clics desde la ficha de producto y no haya ningún campo obligatorio sin marcar" sí lo es, y se comprueba con un test end-to-end.

    Cuando de verdad no se puede —criterios estéticos, tono de los textos, decisiones de marca— déjalo fuera de la spec y márcalo como revisión humana explícita. Lo que no puede pasar es que quede dentro como si el agente pudiera resolverlo.

    ¿Cuánto debe ocupar una spec para un agente de IA?

    No la mides en palabras, la mides en unidades verificables. Una spec debe cubrir un trozo de trabajo que se cierre con una tanda de comprobaciones y una revisión.

    Si la sección "Cómo se verifica" ocupa más de cinco líneas o mezcla áreas del sistema que no comparten test, pártela. Dos specs de 300 palabras funcionan mejor que una de 900.

    ¿La spec sustituye a los tests?

    No, los ordena. La spec dice qué tiene que ser cierto y el test lo comprueba en cada ejecución.

    En la práctica la relación es más estrecha de lo que parece: si los criterios de aceptación están bien escritos, los nombres de tus tests salen casi copiados de ellos. Cuando un criterio no se deja convertir en un nombre de test, casi siempre es que el criterio estaba vago.

    ¿Por qué el agente ignora partes de mi spec?

    Rara vez las ignora. Lo habitual es que las haya interpretado de una forma que a ti no se te ocurrió, porque estaban abiertas a más de una lectura.

    Revisa esas partes buscando dos cosas: adjetivos sin unidad ("rápido", "robusto", "limpio") y sustantivos que en tu proyecto tienen un significado propio ("paginación", "validación", "caché"). Son los dos sitios donde el modelo rellena con lo más común de su entrenamiento en lugar de con lo que hace tu repo.

    ¿Qué hago si el agente toca ficheros que nadie le pidió?

    Añade una sección "Fuera de alcance" a la spec y trátala como parte del contrato, no como una nota al margen. Cinco líneas bastan: qué directorios no se tocan, que no se añaden dependencias, que no se crean migraciones, que no se cambia la forma de respuesta de endpoints existentes y que no se reformatea nada que la feature no toque. Los desastres con agentes casi nunca vienen de lo que no hicieron, sino de lo que hicieron de más, y ninguna spec se lo prohibía.

    ¿La spec tiene que decir cómo implementar la feature?

    No, y decirlo suele empeorar el resultado. Una spec que dicta la implementación línea a línea se puede cumplir al pie de la letra y aun así estar mal, porque el agente reproduce también tus errores de diseño. Una spec que fija el comportamiento observable y el comando que lo verifica no se puede fingir. Tú decides el qué, el agente decide el cómo, y el test decide quién tenía razón.

    ¿Dónde guardo la spec y quién manda si contradice al código?

    En el repositorio, junto al código, y entra en el mismo pull request que la implementación. Fuera del repo se queda desactualizada en semanas y se convierte en contexto falso.

    Cuando spec y código se contradicen, manda el código y la spec se corrige o se borra en ese mismo momento. Déjalo escrito dentro del propio documento: es la línea que evita que el agente tenga que adivinar cuál de las dos fuentes es la buena.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Cuándo NO usar Spec-Driven Development: 6 casos que te frenan

    Cuándo NO usar Spec-Driven Development: 6 casos que te frenan

    Escribí una spec de tres páginas —objetivo, contratos de datos, casos de error, criterios de aceptación— para una integración que no llegó a existir.

    A la mañana siguiente abrí la documentación de la API y descubrí que el endpoint sobre el que se apoyaba la mitad de mis decisiones no devolvía lo que yo daba por hecho. Tiré el documento entero.

    La spec no estaba mal escrita. Estaba escrita antes de tiempo.

    Escribí el libro de Spec-Driven Development. Lo uso casi todos los días y sigo pensando que es la diferencia entre dirigir a un agente y rezarle. Por eso mismo puedo decirte esto sin que suene a excusa: hay trabajo donde SDD no compensa, y confundir "el método funciona" con "el método aplica siempre" te cuesta más horas de las que te ahorra.

    Una spec es un seguro, y a veces la prima cuesta más que el siniestro

    Escribir una spec tiene dos costes.

    El obvio es el tiempo. Ese lo ves y lo aceptas, porque sabes que la vas a recuperar en el primer malentendido que no ocurre.

    El segundo no lo ve casi nadie: una spec fija decisiones. Ese es su trabajo. Y fijar decisiones es fantástico cuando tienes la información para tomarlas, y carísimo cuando no la tienes, porque conviertes una suposición en un contrato y luego construyes encima.

    Todo el debate se reduce a comparar dos cantidades: lo que cuesta el error que la spec previene, y lo que cuesta escribirla ahora, con la información que tienes ahora. Cuando el error es caro e irreversible, la prima es barata a cualquier precio. Cuando el error se arregla con un git revert y un café, estás pagando un seguro contra un rasguño.

    La regla, en una frase: no escribas una spec cuando el coste de deshacer el error sea menor que el coste de escribirla; escríbela siempre que el error no se deshaga con un comando.

    Si has llegado aquí sin el contexto previo, en Spec-Driven Development: evita el caos de la IA está el método entero. Este post es la otra mitad: los seis sitios donde estuve pagando de más hasta que aprendí a mirar la factura.

    1. Cuando todavía no sabes lo que quieres

    Una spec responde a "qué vamos a construir". Un spike responde a "¿esto es siquiera posible?".

    Son preguntas distintas, y la segunda no se contesta escribiendo. Se contesta ejecutando. Cuando estás evaluando si una librería aguanta tu caso, si esa API devuelve lo que promete o si el modelo entiende tus documentos, el código no es la implementación de la decisión: es el instrumento de medida.

    Especificar ahí es adivinar con formato de documento. Y un documento bien maquetado tiene un efecto raro sobre el cerebro: le da a una suposición el aspecto de un hecho.

    Lo que sí necesita un spike son guardarraíles, y son tres:

    1. Una pregunta concreta escrita antes de empezar ("¿puedo procesar 500 facturas en menos de un minuto con este proveedor?"). Si no sabes formularla, no es un spike, es procrastinación con IDE.
    2. Una caja de tiempo. Cuatro horas, un día. Lo que quieras, pero decidido antes.
    3. El compromiso de tirar el código. Rama aparte, sin tests, sin abstracciones. Es YAGNI aplicado al documento: no especifiques por si acaso.

    El peligro real de un spike nunca fue no tener spec. Es que el prototipo se quede. El prototipo demuestra, no se promociona.

    Cuando llega la respuesta, escribes la spec. La exploración no sustituye a la spec: la alimenta. Ese salto del prototipo que demuestra al producto que se sostiene es justo lo que trabajamos en Construye con IA.

    2. Cuando el cambio cabe en tu cabeza y git revert lo deshace

    Subir un timeout. Añadir un índice. Cambiar el copy de un botón. Un campo más en un formulario que ya existe.

    Un diff de veinte líneas, un archivo, reversible en un comando. Escribir spec.md + plan.md + tasks.md para eso no es rigor. Es ceremonia.

    Y la ceremonia hace un daño que no se contabiliza: enseña a todo el mundo —incluido tú— que el proceso es un trámite. En cuanto una spec se percibe como trámite, todas las specs pierden autoridad. También las que sí importaban.

    El test que uso es de tres preguntas. ¿Puedes describir el cambio completo en una frase, sin "y" ni "además"? ¿El diff cabe en una pantalla? ¿Deshacerlo es un comando? Tres síes: abre el editor y hazlo.

    3. Cuando el código no va a sobrevivir a la semana

    Un script para limpiar una tabla una vez. Un notebook para sacar un número que te ha pedido alguien. Un endpoint de debug que borras el viernes.

    Una spec sirve para que otra persona —o tú dentro de seis meses— entienda una decisión. Si no va a haber ni otra persona ni dentro de seis meses, el documento no tiene a quién servir. El criterio de aceptación es ejecutarlo y mirar el resultado.

    La trampa está en otro sitio: el código temporal tiene la mala costumbre de volverse permanente. En cuanto ese script se ejecuta una segunda vez, deja de ser desechable y entra en el caso contrario.

    Mi regla: si dudo, la escribo. La duda ya es la señal de que la tarea es más grande de lo que parecía. Y si escribir la spec te está costando de verdad, echa un vistazo a la anatomía de una spec, porque a lo mejor el problema no es la tarea, es que estás escribiendo cuarenta líneas donde bastaban seis.

    4. Los bugs no se especifican, se reproducen

    Un bug no es una funcionalidad que falta. Es una diferencia entre lo que el sistema hace y lo que ya estaba dicho que tenía que hacer.

    O sea: la especificación ya existe. La escribiste cuando construiste la feature, o vive implícita en el comportamiento que todo el mundo daba por bueno hasta el martes pasado. Escribir un documento nuevo para describir algo que ya está descrito es duplicar la verdad, no aclararla.

    El artefacto correcto es un test que falla.

    Reproduce, aísla, escribe el test en rojo, arréglalo, deja el test dentro. Ese test es la spec de ese bug, con una ventaja que ningún markdown te da: es ejecutable, y cuando envejece te avisa el CI. Si alguien vuelve a romper eso dentro de seis meses, se entera antes que tú. Cómo se combina eso con dejar que la IA escriba la implementación lo desarrollé en TDD y spec-first con IA.

    Hay dos excepciones. La primera: nadie sabe decirte cuál sería el comportamiento correcto. Eso no es un bug, es un requisito sin decidir disfrazado de bug, y sí se especifica. La segunda: sabes perfectamente qué tiene que pasar, pero el arreglo es más grande que el fallo —rehacer la caché, tocar el modelo de concurrencia, cambiar un contrato que ya consume alguien—. El test sigue siendo obligatorio, pero describe el síntoma, no el rediseño. Eso se especifica igual.

    5. Cuando el dominio cambia bajo tus pies

    Si el requisito muda cada semana, la spec envejece más rápido de lo que tardas en ejecutarla. Y entonces tienes dos verdades: el documento y el código.

    Cuando hay dos verdades, los humanos resuelven el conflicto solos: dejan de leer el documento. Molesto, pero se sobrevive.

    El problema es el agente. Un agente no distingue una spec vigente de una obsoleta. No tiene forma de saber que ese párrafo lo invalidó una llamada del jueves. La lee, la trata como fuente de verdad y construye encima con toda la seguridad del mundo.

    La salida no es abandonar el método, es acortar el alcance. Specs de una semana en vez de specs de un trimestre. Especifica la parte del dominio que ya está congelada y deja explícitamente marcado lo que sigue en discusión. Una sección de "esto todavía no está decidido" vale más que tres páginas de decisiones falsas.

    6. Cuando la spec se ha convertido en teatro

    El síntoma es fácil de reconocer: escribes la spec después de tener el código.

    Eso no es Spec-Driven Development. Es documentación retroactiva, que no tiene nada de malo salvo el nombre que le pongas. El valor de la spec está en el orden, no en el archivo. Si el código ya existe, el documento no puede cambiar ni una sola decisión, que era exactamente para lo que servía.

    Hay dos síntomas más. El primero: nadie la lee, y lo sabes porque nadie te ha discutido nunca una línea. El segundo: las specs se copian de la anterior cambiando los nombres.

    Cuando aparece cualquiera de los tres, el problema no es el método. Es que lo estás aplicando en tareas donde no aportaba, y la gente lo ha notado antes que tú.

    Cuándo usar Spec-Driven Development y cuándo no: la tabla

    Tipo de trabajo ¿Spec? Por qué
    Spike para saber si algo es viable No — pregunta y caja de tiempo El código es la investigación; la spec fijaría decisiones sin información
    Cambio pequeño y reversible No — el propio diff Revertirlo cuesta menos que documentarlo
    Bug reproducible No — un test en rojo El test fija el comportamiento y además lo vigila el CI
    Código que no sobrevive a la semana No — el propio código El documento no tiene a quién servir
    Spec escrita después del código No — llámalo documentación Ya no puede cambiar ninguna decisión, que era su único trabajo
    Requisito que cambia cada semana Corta y con caducidad La spec envejece más rápido de lo que se ejecuta
    Feature nueva en un producto vivo Sí Otra persona la va a tocar y el error se paga meses después
    Migración o cambio del modelo de datos Sí, siempre El error no se deshace con git
    Trabajo que cruza servicios o equipos Sí, siempre La spec es el punto de sincronización, no el papeleo
    Tarea que delegas entera a un agente Sí, siempre Lo que no escribas, lo rellena inventando
    Auth, pagos, datos personales Sí, siempre El coste del fallo no es técnico

    Bajar de artefacto no es dejar de pensar

    La alternativa a una spec no es el caos: es un artefacto más barato. Hay cinco niveles, y solo el primero es una spec completa.

    1. Spec completa — spec, plan y tareas. Para trabajo caro, compartido o delegado entero.
    2. Spec corta — tres párrafos: objetivo, criterio de aceptación y qué queda fuera. El escalón que más uso.
    3. Un plan — el modo plan de Claude Code, leído y aprobado antes de que toque nada. Treinta segundos de lectura que evitan revisar un diff de novecientas líneas, como conté en cómo usar Claude Code a diario.
    4. Un test que falla — para bugs y para cualquier cosa con un criterio binario.
    5. Nada — y el diff es toda la conversación.

    La pregunta buena nunca fue "¿spec sí o spec no?". Es: ¿cuál es el artefacto más barato que evita que esto salga mal?

    Dónde Spec-Driven Development gana siempre

    La tabla ya dice dónde la spec no se discute: migraciones, modelo de dominio, auth, dinero. Nada de eso es nuevo. Lo que ha cambiado la ecuación, desde que los agentes de código empezaron a ejecutar tareas de varias horas sin supervisión, es la última fila: el trabajo que delegas entero a un agente.

    Antes la spec competía contra "lo hago yo, que ya me entiendo". Ahora compite contra revisar cuatrocientas líneas que alguien escribió interpretando lo que tú no llegaste a decir. Cuando delegas, cada hueco de la especificación se rellena con una invención plausible, y las invenciones plausibles son las más caras de detectar. Lo desarrollé en qué pasa cuando pides código sin spec.

    En ese escenario la spec deja de ser documentación. Es el prompt más caro que vas a escribir, y el único que se amortiza.

    Lo que haría yo mañana

    Coge la siguiente tarea de tu lista y hazte una sola pregunta antes de abrir el editor:

    Si esto sale mal, ¿cuánto cuesta deshacerlo?

    Si la respuesta es "un git revert", empieza a picar. Si la respuesta es "una migración de datos", "una llamada con otro equipo" o "un incidente en producción", escribe la spec antes de tocar una línea.

    No necesitas más criterio que ese. Los seis casos de este post son solo ejemplos de esas dos respuestas.

    El libro de Spec-Driven Development va justo de esto: hay un capítulo entero sobre la spec más corta que puedes escribir, además de las plantillas, el flujo con el agente y qué hacer cuando la spec y el código se separan. Si prefieres ver cómo lo aplica gente que ya lo tiene metido en su día a día, esa conversación pasa en Dominicode Labs.

    Saber cuándo no usar un método es la parte que nadie te enseña, y es la que separa aplicarlo de entenderlo.

    Preguntas frecuentes

    ¿Entonces Spec-Driven Development no sirve para proyectos pequeños?

    Sirve, pero el tamaño del proyecto no es la variable correcta. La variable es cuánto cuesta deshacer la tarea si sale mal y cuánta gente toca ese código. Un proyecto pequeño con una migración de datos y un cobro de por medio necesita spec. Un proyecto enorme donde vas a cambiar el texto de un botón, no. Y si dudas, escríbela: la duda suele significar que la tarea es más grande de lo que parecía.

    ¿Qué escribo en lugar de una spec cuando la tarea no la necesita?

    Bajas un escalón de artefacto, no bajas a cero. Hay cinco: spec completa, spec corta (objetivo, criterio de aceptación y qué queda fuera), un plan aprobado antes de tocar código, un test que falla, y nada. La mayoría del trabajo diario vive en los escalones dos y tres, no en el uno. La pregunta útil no es "¿spec sí o no?" sino cuál es el artefacto más barato que evita que eso salga mal.

    ¿Qué escribo en lugar de una spec cuando arreglo un bug?

    Un test que falla. Reproduce el fallo, aísla el caso mínimo, escribe el test en rojo, arregla el código y deja el test dentro del repositorio. Ese test cumple la misma función que una spec —fijar el comportamiento esperado— con dos ventajas: es ejecutable y el CI lo comprueba solo. La excepción es cuando nadie sabe cuál debería ser el comportamiento correcto; eso no es un bug, es un requisito sin decidir, y ese sí se especifica.

    ¿Puedo escribir la spec después de tener el código?

    Puedes, pero llámalo por su nombre: documentación. El valor de una spec está en el orden, porque su trabajo es cambiar decisiones antes de que se conviertan en código. Escrita después, no puede cambiar ninguna. Sirve para onboarding y para dejar constancia, y eso tiene su utilidad, pero no está gobernando nada.

    ¿Qué hago si los requisitos cambian cada semana?

    Acorta el alcance de la spec en lugar de abandonarla. Especifica solo la parte del dominio que ya está cerrada, marca de forma explícita lo que sigue en discusión y ponle caducidad al documento. El riesgo grande no es no tener spec, es tener una obsoleta: un agente no sabe distinguirla de una vigente y construirá encima con total seguridad.

    ¿Y si voy a delegar la tarea completa a un agente de código?

    Entonces escribe la spec aunque la tarea parezca pequeña. Cuando delegas, cada hueco que dejes sin especificar lo rellena el modelo con una suposición razonable, y esas suposiciones son las más difíciles de detectar revisando el diff. Ahí la spec no compite contra tu tiempo de escribir código: compite contra tu tiempo de revisar código ajeno, que siempre es más caro.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.