Si has trabajado con Alembic, con las migraciones de Django o con Flyway, ya conoces la idea que hay detrás de las capacidades y deltas de DGC aunque no lo sepas. El esquema de tu base de datos no está escrito en ningún documento. Es el resultado de aplicar, en orden, todas las migraciones desde la primera. Nadie mantiene a mano un «esquema_actual_final_v3.sql»: si quieres saber cómo es la base de datos hoy, aplicas la historia.
Pues en DGC el sistema se describe igual: cada capacidad es una pieza de comportamiento con nombre propio, y cada cambio es un delta que la modifica. El sistema de hoy es la suma ordenada de todos esos deltas.
En el artículo anterior te conté que el spec-driven development recupera la ingeniería de requisitos porque ahora la spec la lee un agente, y te dejé pendiente esto: cómo organizar las specs de un sistema entero sin que se conviertan en un documento que nadie se cree. Vamos a ello.
El problema del documento único
La forma clásica de especificar un sistema es un documento grande. Alguien lo escribe al principio, con mucho cariño, y durante unas semanas es la referencia. Después llegan los cambios: un ticket por aquí, una conversación en el pasillo por allá, un «esto lo cambiamos directamente en el código, que es una tontería». Al cabo de unos meses, el documento dice una cosa y el sistema hace otra. Seguro que lo has vivido.
Mientras quien leía ese documento era una persona, la cosa más o menos aguantaba. Sabías que estaba desactualizado y preguntabas. Un agente no pregunta. Lee la spec al pie de la letra y, si la spec miente, el agente construye sobre esa mentira con toda la tranquilidad del mundo.
Así que si la spec va a ser la fuente de verdad (y en DGC lo es, es su primera idea), necesita dos cosas que el documento único no tiene: estar siempre al día y guardar la historia de por qué es como es. Eso es lo que resuelven las capacidades y deltas.
Capacidades y deltas: las dos piezas del modelo
Una capacidad es una unidad de comportamiento con identidad propia que perdura en el tiempo. No es una pantalla ni un módulo del código. Es algo que el sistema sabe hacer y que tiene sentido por sí mismo. El ejemplo que uso en el documento de DGC es recuperacion-password.
Cada capacidad vive en su propia ficha, con su propósito, su contrato (los endpoints o comandos públicos), sus criterios de aceptación, sus restricciones, lo que queda fuera de alcance, sus dependencias, las dudas abiertas y el historial. Te enseño una versión resumida:
---
id: recuperacion-password
nombre: Recuperación de contraseña
prefijo: RP
estado: activa
revision: 3
---
## Propósito
Permitir que un usuario registrado recupere el acceso a su cuenta
sin intervención de soporte.
## Contrato
- POST /auth/password-recovery { email }
- POST /auth/password-reset { token, nueva_password }
## Criterios de aceptación
- RP.1 Cuando un usuario solicite recuperar la contraseña con un email
registrado, el sistema deberá enviarle un enlace de recuperación.
- RP.2 El enlace deberá caducar 30 minutos después de su emisión.
- RP.3 El enlace deberá ser de un solo uso.
- RP.4 Si el email no está registrado, el sistema deberá responder
exactamente igual que en RP.1.
## Restricciones
- RP.R1 El correo deberá enviarse en menos de 1 minuto.
- RP.R2 Máximo 5 solicitudes por email y hora.
## Fuera de alcance
- Recuperación por SMS.
## Historial
- r3 (Δ-123): enmienda RP.2 — caducidad de 60 a 30 minutos.
- r2 (Δ-087): adición de RP.4.
- r1 (Δ-041): creación.
¿Te suena la sintaxis de los criterios? Es EARS, la plantilla de Rolls-Royce de la que te hablé en el artículo anterior: «Cuando ocurre algo, el sistema deberá hacer esto».
Fíjate en la cabecera: revision: 3. Una capacidad cambia, pero sigue siendo la misma. recuperacion-password en su revisión 1, 2 o 3 es siempre la misma capacidad, igual que una tabla sigue siendo la misma tabla aunque le añadas columnas. La revisión vigente es la que manda.
Y cada revisión llega por un delta: un conjunto ordenado de cambios sobre una o varias capacidades, junto con sus contrapruebas. En DGC, un encargo es un delta. Si lees el historial de abajo arriba, ves la vida de la capacidad:
- Δ-041 la crea (r1), con la caducidad del enlace en 60 minutos.
- Δ-087 añade RP.4 (r2): si el email no existe, se responde igual que si existiera.
- Δ-123 enmienda RP.2 (r3): la caducidad baja de 60 a 30 minutos.

Aquí está la gracia del modelo. Se guardan las dos cosas:
- El estado vigente: el fichero de cada capacidad tal y como está hoy. Es lo que lee cualquiera, persona o agente, para saber qué es verdad ahora mismo. No hace falta reconstruir nada.
- Los deltas: el historial del control de versiones más la sección Historial de la ficha. Esa sección recoge la intención de cada cambio, que es justo lo que un diff no te cuenta. Un diff te dice que un 60 pasó a ser un 30. El historial te dice que fue una enmienda de RP.2 y en qué encargo se decidió.
Un detalle que parece menor y no lo es: los IDs. RP.2 sigue siendo RP.2 aunque cambie su contenido, y un ID derogado no se reutiliza nunca. Si mañana se elimina RP.3, el siguiente criterio será RP.5. ¿Por qué tanto cuidado? Porque las contrapruebas apuntan a esos IDs. Si reutilizas uno, una contraprueba antigua acabaría apuntando a un criterio nuevo que no tiene nada que ver con ella, y nadie se daría cuenta. Es como reutilizar el número de una migración que ya se aplicó en producción. Mal vamos.
Los seis tipos de delta
No todos los cambios son iguales, y aquí el modelo de capacidades y deltas se pone estricto. Cada delta tiene un tipo, y el tipo dice qué cambia en la spec y qué pasa con las contrapruebas:
| Tipo | Qué cambia en la spec | Qué pasa con las contrapruebas | Ejemplo |
|---|---|---|---|
| Adición | Nueva capacidad, criterios o restricciones | Se escriben nuevas | Añadir recuperación de contraseña |
| Enmienda | Criterios o restricciones modificados | Se reescriben las afectadas y se retiran las huérfanas | La caducidad pasa de 60 a 30 minutos |
| Derogación | Se eliminan capacidades, criterios o restricciones | Quedan huérfanas y se retiran | Eliminar el login con usuario y contraseña |
| Bug | Depende de qué falló | Siempre se añade la que faltaba | — |
| Refactor | Nada | Las funcionales no se tocan y deben pasar todas | Separar el módulo de pagos |
| Cimientos | Spec de sistema | Técnicas | Scaffolding, dependencias, CI, versión del lenguaje |
Las tres primeras son las que esperarías: añadir, modificar y quitar. Las otras tres son las que más dudas generan, así que me detengo en ellas.
El bug no es un tipo de artefacto, es algo que hay que clasificar. Cuando aparece un fallo, la pregunta es qué ha fallado de verdad:
- A. El código no cumple la spec y ninguna contraprueba lo detectó. Faltaba una contraprueba. Se añade la que reproduce el bug, la spec no cambia y el agente corrige contra la spec vigente. Es el único delta en el que el código cambia sin que cambie la spec.
- B. La spec era ambigua o incompleta. Faltaba precisión. Se hace una enmienda que aclara el criterio, con su contraprueba.
- C. El sistema cumple la spec, pero la spec estaba mal. Esto ya no es un bug de código, es un error de validación. Enmienda, como cualquier cambio de requisito.
En los tres casos hay algo común: siempre se añade la contraprueba que faltaba. Si un bug se coló una vez, que no se cuele dos.
El refactor es el delta con las contrapruebas funcionales congeladas. No toca la spec y todas las contrapruebas funcionales tienen que seguir pasando sin cambiar ni una coma. Si para tu «refactor» tienes que tocar una contraprueba funcional, no es un refactor: estás cambiando comportamiento y te toca una enmienda. Y una mejora de rendimiento tampoco es un refactor, aunque lo parezca. Es una enmienda de una restricción («p95 por debajo de 200 ms»), con su contraprueba técnica.
Los cimientos son la implementación de la spec de sistema. El scaffolding, el fichero de dependencias, la estructura de carpetas o el pipeline de CI tienen que salir de algún sitio. En DGC, el primer delta de cualquier proyecto es un delta de cimientos, y sus contrapruebas son técnicas: las dependencias se instalan, el linter pasa, la aplicación arranca y responde al healthcheck, y el CI se ejecuta.
Una cosa más que se olvida mucho: en cuanto un sistema está en producción, hay datos creados con revisiones anteriores de la spec. Así que toda enmienda tiene que decir qué pasa con esos datos y, si hace falta, incluir una migración con su propia contraprueba. Las migraciones de verdad, vaya.
Criterio, restricción y decisión técnica
Dentro de una ficha no todo es lo mismo. En SDD se repite mucho que la spec describe el qué y no el cómo. Estoy de acuerdo, pero con un matiz importante: la seguridad, el rendimiento o los límites forman parte del qué, porque se pueden observar desde fuera.
| Tipo | Pregunta | Ejemplo | Dónde va |
|---|---|---|---|
| Criterio de aceptación | ¿Qué hace y cuándo? | «Si el email existe, se envía un enlace de recuperación» | Capacidad |
| Restricción | ¿Con qué calidad y dentro de qué límites? | «En menos de 1 minuto; máximo 5 solicitudes por hora» | Capacidad, o sistema si es transversal |
| Decisión técnica | ¿Cómo se construye? | «Los endpoints no acceden directamente a la base de datos» | Spec de sistema |
La regla práctica que uso: si algo se puede medir u observar sin mirar el código, es una restricción. Si dicta cómo se construye, es una decisión técnica.
Y ojo con no confundir una condición con una restricción. «Si el email no está registrado…» es una condición: forma parte del criterio, es el «Dado…» del comportamiento. «En menos de 1 minuto» es una restricción: describe la calidad de ese comportamiento.
¿Por qué tanto empeño en separarlos? Porque se verifican de forma distinta. Los criterios se comprueban con contrapruebas funcionales, que el agente implementador nunca ve. Las restricciones y las decisiones técnicas se comprueban normalmente con contrapruebas técnicas (una prueba de carga, una regla de dependencias entre módulos, un escáner de secretos), que pueden ser visibles, porque la regla misma es la prueba y no hay ejemplos que memorizar. Por eso la convención de IDs distingue el tipo en el propio nombre: RP.2 es un criterio y RP.R1, una restricción. El CI puede tratarlos por separado sin abrir la ficha.
Spec de sistema frente a spec de capacidad
Te habrás fijado en que la decisión técnica no va en la capacidad. Va en otro sitio: la spec de sistema.
DGC trabaja con dos niveles:
- La spec de sistema es un documento único con lo que vale para todo: el stack, la arquitectura, las decisiones técnicas globales y las restricciones transversales, como «toda respuesta en menos de 500 ms».
- Las capacidades describen comportamiento. Puede ser algo visible para el usuario o un requisito técnico propio de esa capacidad, como los reintentos al llamar a la API externa de pagos.
Sin el nivel de sistema, las reglas globales acaban repetidas en todas las capacidades o, lo más habitual, en ninguna. Y sin el nivel de capacidad vuelves al documento único que te contaba al principio.
Los dos niveles evolucionan con deltas, así que el modelo de capacidades y deltas no se rompe al subir de nivel. Las capacidades cambian con adiciones, enmiendas y derogaciones. La spec de sistema nace con el delta de cimientos y, si un día cambias de stack o de herramientas, eso es una enmienda a la spec de sistema. Todo pasa por el mismo sitio.
OpenSpec: de dónde salen las capacidades y deltas, y qué añade DGC
No me quiero colgar medallas que no son mías. La idea de organizar las specs por capacidad y trabajar con deltas no la he inventado yo. Viene de OpenSpec, la herramienta de Fission-AI que ya salió en el artículo anterior.
OpenSpec separa dos carpetas: specs/, que es la fuente de verdad y describe cómo se comporta el sistema hoy, y changes/, donde cada cambio vive en su propia carpeta con su propuesta, su diseño, sus tareas y sus delta specs. Esas delta specs se escriben por secciones: ADDED Requirements, MODIFIED Requirements y REMOVED Requirements. Cuando el cambio se archiva, los deltas se fusionan con las specs principales y la carpeta del cambio se mueve al archivo con la fecha delante, para conservar el contexto. Una enmienda como la de la caducidad tendría esta pinta:
## MODIFIED Requirements
### Requirement: Caducidad del enlace de recuperación
El enlace SHALL caducar 30 minutos después de su emisión.
(Previously: 60 minutos)
Es el modelo de las migraciones aplicado a las specs, y me parece una muy buena idea. Por eso DGC lo toma tal cual: estado vigente por capacidad, más cambios que se aplican en orden.
Lo que DGC añade encima son dos cosas:
- Revisiones numeradas con historial dentro de la ficha. Cada capacidad sabe en qué revisión está y qué criterios y restricciones cambiaron en cada una, y en qué delta. No tienes que ir a buscar al archivo de cambios para entender por qué RP.2 dice 30 minutos.
- Más tipos de delta, cada uno con sus reglas de verificación. OpenSpec tiene añadir, modificar y eliminar, que en DGC son adición, enmienda y derogación. DGC suma bug, refactor y cimientos. Y lo importante no es el nombre, sino que cada tipo dice qué pasa con las contrapruebas: el bug siempre añade la que faltaba, el refactor congela las funcionales y los cimientos se verifican con contrapruebas técnicas.
Esa segunda parte es la que tiene más miga, porque es donde el modelo de specs se engancha con la verificación. Y es lo que le falta al spec-driven development, como te contaba la semana pasada.
Lo que queda por contar
Hay una consecuencia de todo esto que no quiero dejar pasar. Con una enmienda, algunas contrapruebas de revisiones anteriores dejan de ser válidas. Si RP.2 pasa de 60 a 30 minutos, la contraprueba que comprobaba que un enlace de hace 45 minutos todavía funcionaba ya no vale. Así que la relación entre criterios y contrapruebas no es 1:1 a lo largo del tiempo: el conjunto de contrapruebas vigente tiene que reflejar la spec de hoy, no la suma de todas las que se han escrito.
Y aquí entra la pregunta obvia: ¿qué es exactamente una contraprueba, quién la escribe y cómo se le esconde al agente? Eso es el próximo artículo de la serie, que es el corazón de DGC.
Mientras tanto, si quieres ver el modelo completo de capacidades y deltas, con las fichas, los identificadores y todos los tipos de delta, lo tienes en la página de DGC.
¡Te espero!




