> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# El sistema de especificaciones

> Cómo un módulo pasa de una idea a código mergeado, y cómo demostramos después qué se decidió, cuándo, por qué y por quién. Este es el manual operativo; el README.md del repositorio lleva la versión corta para quien llega por primera vez.

> Traducción. Autoritativo: [`../../modules/README.md`](/modules/overview).

El modelo está tomado prestado, no inventado: una propuesta numerada y versionada con estructura
obligatoria, un estado de ciclo de vida y un registro del release que la implementó — el mecanismo que
Kubernetes usa para los KEP, IETF para los RFC y Python para los PEP. Lo que agregamos es la lección
de Backstage: si la trazabilidad vive en prosa, nadie la consulta. La nuestra vive en frontmatter
validado.

***

## 1. Diccionario

| Término            | Qué es                                                                                                               | Dónde vive                       | Cómo se versiona     | Cambia por                                |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------- | ----------------------------------------- |
| **DEC**            | Una decisión de diseño cerrada de las rondas de debate. El vocabulario que citan todos los demás documentos.         | `design/decision-registry-v1.md` | versión del registro | un ADR nuevo que la supere                |
| **ADR**            | Architecture Decision Record. *Por qué* se tomó una decisión técnica transversal. Una serie para toda la plataforma. | `adr/`                           | campo de estado      | un ADR que lo supere                      |
| **Estándar**       | Las reglas MUST/NEVER de un área completa (datos, eventos, jobs, api…). Aplica a todo módulo.                        | `standards/`                     | v1, v2               | en sitio, con revisión                    |
| **PRD**            | Product Requirements Document. Qué es un módulo, para quién, qué significa el éxito. Uno por módulo.                 | `modules/{m}/prd.md`             | **semver**           | versión nueva + changelog                 |
| **Spec de módulo** | La forma técnica viva de un módulo: entidades, invariantes, eventos, endpoints. Siempre refleja la realidad.         | `modules/{m}/spec.md`            | no se versiona       | se edita libremente; describe lo que *es* |
| **FS**             | **Feature Spec.** La unidad de entrega: un incremento que se puede lanzar solo.                                      | `modules/{m}/features/`          | **semver**           | versión nueva + changelog                 |
| **TS**             | Task Spec. El plan de ejecución para un agente. **Opcional** — solo cuando una feature necesita más de un slice.     | `task-specs/`                    | no se versiona       | se reescribe por intento                  |
| **Slice**          | Un arquetipo canónico de implementación que los agentes copian. Existen dos: comando síncrono y pipeline asíncrono.  | `slices/`                        | SPEC → WALKTHROUGH   | cuando cambia el código de referencia     |
| **Runbook**        | Qué hace una persona cuando algo se rompe.                                                                           | `runbooks/`                      | no se versiona       | se edita libremente                       |

Dos trampas de vocabulario que vale la pena nombrar:

* **Spec de módulo ≠ Feature Spec.** El spec de módulo es un *mapa de lo que existe* y se edita
  libremente. Un Feature Spec es un *contrato para un cambio* y se congela al aprobarse.
* **FS ≠ TS.** El FS dice qué construir y cómo sabremos que está listo. El TS dice cómo construirlo.
  Una feature chica no necesita TS — el FS lleva una sección *Ejecución* en su lugar.

## 2. La cadena

```
DEC-*  ──►  ADR  ──►  PRD  ──►  Spec de módulo  ──►  FS  ──►  TS (opcional)  ──►  PR
 la          el       qué es    qué existe          la        cómo lo ejecuta    y el PR
 decisión    por qué  y para    ahora mismo         unidad    el agente          enlaza de
                      quién                         de entrega                   vuelta al FS
```

Cada eslabón es verificable. Un FS que cita un DEC inexistente falla CI; un FS marcado `implemented`
sin PR registrado falla CI; una tabla del spec de módulo que ningún FS reclama se reporta como sin
cobertura.

## 3. Identificadores

`FS-{MODULE}-{NNNN}` — cuatro dígitos, para que un módulo pueda tener hasta 9999 feature specs sin
renumerar. Códigos de módulo:

| Código | Módulo        |
| ------ | ------------- |
| `IDN`  | identity      |
| `CORE` | customer-core |
| `LOY`  | loyalty       |
| `MSG`  | messaging     |
| `CRM`  | crm           |

Ejemplos: `FS-LOY-0002`, `FS-CORE-0014`. La numeración es **por módulo** — los módulos crecen a
ritmos distintos y una secuencia global obligaría a coordinar para nada. Los números nunca se
reutilizan, ni siquiera después de retirar un spec.

Una feature que genuinamente cruza módulos pertenece a `core`, o son dos feature specs con un
`depends_on` entre ellos. Nunca es un FS archivado bajo dos módulos.

## 4. Versionado

Dos esquemas distintos, deliberadamente:

| Qué                               | Esquema                        | Por qué                                                                                                                                                                                                                |
| --------------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Documentos de spec** (PRD, FS)  | **Semver** `MAJOR.MINOR.PATCH` | Un spec describe un contrato. Major = el contrato cambió y los consumidores deben reaccionar. Minor = se agregó algo. Patch = redacción, sin cambio de comportamiento. Calza con la política de deprecación de la API. |
| **Todo proyecto del repositorio** | **CalVer** `YYYY.M.PATCH`      | Entregamos una suite, no una librería. Nadie depende de las versiones de nuestros paquetes internos, así que una fecha informa más que un semver que nadie lee.                                                        |

Un spec parte en `0.1.0` en `draft`. Llega a `1.0.0` en el momento en que se `approved` — eso es lo
que *significa* aprobar: el contrato ya es lo bastante estable como para construir contra él.

## 5. Ciclo de vida

```
draft ──► review ──► approved ──► in-progress ──► implemented
                         │
                         └──────► superseded  |  withdrawn
```

| Estado        | Significa                                                                          | Quién lo mueve          |
| ------------- | ---------------------------------------------------------------------------------- | ----------------------- |
| `draft`       | Se está escribiendo. Todo puede cambiar.                                           | autor (humano o agente) |
| `review`      | Completo y esperando la decisión del owner.                                        | autor                   |
| `approved`    | **Contrato congelado.** La versión pasa a `1.0.0`. Ya se puede escribir código.    | solo el owner           |
| `in-progress` | Un TS o un PR lo está ejecutando.                                                  | quien inicie el trabajo |
| `implemented` | Mergeado y verificado, con registro de entrega.                                    | el PR que mergea        |
| `superseded`  | Reemplazado. Debe nombrar al FS que lo reemplaza.                                  | el FS que lo supera     |
| `withdrawn`   | Se decidió no hacerlo. **Se conserva para siempre** — el razonamiento es el valor. | owner                   |

### Las dos reglas que hacen de esto un sistema y no una carpeta

> **R-S1 — No se mergea código de una feature cuyo FS no esté `approved`.**
> El PR declara su id de FS; CI lee el estado de ese spec y bloquea si no.

> **R-S2 — Un FS `approved` es inmutable en sus secciones normativas.**
> Cambiarlo no es editarlo: subir la versión y agregar una fila de changelog con qué cambió y por qué.
> Si el cambio revierte un DEC o un ADR, ese ADR se escribe *primero*.

Las secciones normativas son: Alcance, Fuera de alcance, Comportamiento, Datos, API, Eventos y
Criterios de aceptación. Contexto, Notas y Preguntas abiertas se pueden editar libremente en cualquier
estado.

## 6. Frontmatter — el contrato máquina-legible

Todo FS lo lleva. Los validadores lo leen; nada acá es decoración.

```yaml theme={null}
---
id: FS-LOY-0002
title: Points Ledger
module: loyalty
type: feature-spec
version: 1.2.0
status: implemented
phase: F1a                         # F1a | F1b | F2
archetype: synchronous-command     # o asynchronous-pipeline, o none
owner: daniel
depends_on: [FS-LOY-0001]
supersedes: []
decisions: [DEC-B5, DEC-H3]        # los DEC-* que implementa
adrs: [ADR-011, ADR-017]           # los ADR de los que depende
tables:    [loyalty.ledger_transactions, loyalty.point_lots]
events:    [loyalty.points.earned, loyalty.points.expired]
endpoints: []                      # "MÉTODO /v1/ruta — permiso"
created: 2026-08-17
updated: 2026-09-15
implementation:
  - version: 1.0.0
    task_spec: TS-004
    pr: 142
    merged: 2026-09-01
    by: daniel + claude-opus-5
    verified_in: cert
---
```

`tables`, `events` y `endpoints` son lo que usa el validador de cobertura: cada entidad de un spec de
módulo debe estar reclamada por exactamente un FS. Así descubrimos que algo se diseñó y nunca se
asignó a una entrega.

La sección **Registro de entrega** del cuerpo se *genera* desde `implementation`. Nunca se escribe a
mano — la misma disciplina que un modelo de datos generado.

## 7. Escribir un módulo, paso a paso

1. **PRD.** Un documento, desde [`TEMPLATE-prd.md`](/es/modules/TEMPLATE-prd). Para quién es, qué trabajos
   hace, no-objetivos explícitos, cómo se mide el éxito, implicancias de pricing, fases. Se escribe
   una vez, se revisa, y después casi no se toca. Escríbelo antes del diseño técnico — si el PRD
   cuesta escribirlo, el módulo todavía no se entiende.
2. **Spec de módulo.** La forma técnica: entidades e invariantes, eventos emitidos, endpoints con el
   único permiso que declara cada uno, puntos de extensión. Este queda vivo y se edita cuando la
   realidad cambia.
3. **Descomponer en features.** Cortar por *incrementos que se pueden lanzar solos*, no por tablas. La
   prueba: ¿esto se puede lanzar solo y vale algo? Si no, es una sección dentro de otro FS. Registrar
   la lista resultante en el hub del módulo como tabla de hoja de ruta.
4. **Escribir cada FS** desde [`TEMPLATE-feature-spec.md`](/es/modules/TEMPLATE-feature-spec), en orden de
   dependencia. Estado `draft` → `review` → el owner aprueba → `1.0.0`.
5. **Ejecutar.** Feature chica: la sección *Ejecución* del FS basta. Más grande: abrir un TS que
   declare su arquetipo. El agente trabaja desde el FS aprobado, no desde un prompt de chat — ese es
   todo el punto del sistema.
6. **Mergear y registrar.** El PR agrega una entrada de `implementation` y mueve el estado a
   `implemented`. Después se actualiza el spec de módulo para que refleje lo que ahora existe.

## 8. Idiomas

La documentación de módulos se entrega en **inglés y español**, para que cualquier persona pueda leer
y revisar un módulo completo.

* **El inglés es autoritativo.** `modules/{m}/` es la versión normativa: es lo que leen los agentes,
  lo que valida CI, y lo que manda ante cualquier discrepancia.
* **El español es una traducción fiel**, no una variante. Vive en `es/modules/{m}/` y refleja el árbol
  exactamente, archivo por archivo. Una traducción que dice algo distinto del original es un defecto,
  no una decisión local.
* Ambas llevan el **mismo frontmatter** — mismo `id`, `version` y `status`. El validador `translation`
  falla cuando divergen, que es lo que impide que una subida de versión deje al español atrás en
  silencio.
* Todo archivo traducido abre nombrando su original autoritativo.

El paquete legal va en la dirección contraria: el español es el autoritativo y la traducción al inglés
lleva un banner de no vinculante, porque un documento legal en inglés puede terminar firmado como si
rigiera.

## 9. Validación

```bash theme={null}
pnpm docs:validate          # modo reporte — imprime hallazgos, sale con 0
pnpm docs:validate:strict   # modo CI — cualquier hallazgo falla el build
pnpm docs:validate:mint     # lo que el propio Mintlify dirá del build
```

| Validador     | Qué detecta                                                                                                  |
| ------------- | ------------------------------------------------------------------------------------------------------------ |
| `frontmatter` | Campos faltantes o mal formados, status/phase/archetype inválidos, semver malo, `updated` antes de `created` |
| `coverage`    | Una tabla, evento o endpoint de un spec de módulo que ningún FS reclama — o que dos FS reclaman              |
| `graph`       | `depends_on`, `supersedes`, `DEC-*` y `ADR-*` que no resuelven; ciclos de dependencia                        |
| `status`      | `implemented` sin registro de entrega · `superseded` sin destino · `approved` todavía en `0.x`               |
| `changelog`   | Versión del frontmatter que no coincide con la última fila del changelog                                     |
| `translation` | Un documento de módulo sin espejo en español, o un espejo cuyo `id`/`version`/`status` discrepa del original |
| `links`       | Un enlace relativo, con sufijo `.md`, o que no apunta a ninguna página                                       |
| `navigation`  | Una página de `docs.json` sin archivo, un archivo en ninguna navegación, una página llamada `README`         |

El modo reporte es el default mientras los módulos se siguen descomponiendo; `strict` es lo que corre
CI. `docs:validate:mint` corre el CLI del propio Mintlify. Deliberadamente **no** está pinneado ni
es una compuerta de CI: valida contra un producto hosteado que publica varias versiones al día, así
que pinnearlo nos verificaría contra un contrato viejo. Córrelo antes de subir documentación; las
reglas que ya conocemos están codificadas en `links` y `navigation`, que sí son deterministas.

## 9b. Escribir para Mintlify

Tres restricciones no son obvias, y cada una produjo silenciosamente un 404 en vez de un error.

> **`.md` se parsea como MDX.** Un `<` suelto seguido de algo que no es una letra se lee como el
> inicio de una etiqueta JSX y mata la página. Los presupuestos de latencia son el caso común:
> escribe `p95 &lt;300 ms`, no `p95 <300 ms`. Una `{` suelta abre una expresión JavaScript —
> escápala como `\{`, o pon el token entre backticks. Los comentarios HTML fallan igual: usa
> `{/* ... */}`, nunca `<!-- ... -->`. Dentro de bloques de código y de spans en backticks nada de
> esto aplica.

> **Una página nunca puede llamarse `README.md`.** Mintlify omite esos archivos por completo; la
> navegación queda apuntando a una página que, para el build, no existe. Los overviews de sección
> son `overview.md`. El único `README.md` en `docs/internal/` es deliberado: es el archivo que ve
> GitHub, y es el único lugar donde los enlaces relativos con sufijo `.md` son correctos.

> **Los enlaces resuelven desde la raíz de la documentación, no desde el archivo.** Un enlace cuyo
> destino se escribe `data.md` funciona en GitHub y da 404 en el sitio, y un `standards/data` pelado
> también. Todo enlace interno es absoluto y sin extensión: `/standards/data`.

Los validadores `links` y `navigation` hacen cumplir las tres.

## 10. Índice de módulos

| Módulo                                        | PRD                              | Spec                               | Features    | Estado                               |
| --------------------------------------------- | -------------------------------- | ---------------------------------- | ----------- | ------------------------------------ |
| [`identity`](/es/modules/identity/overview)   | [prd](/es/modules/identity/prd)  | [spec](/es/modules/identity/spec)  | 9 escritos  | completo, EN + ES, todos `draft`     |
| [`core`](/es/modules/core/overview)           | [prd](/es/modules/core/prd)      | [spec](/es/modules/core/spec)      | 14 escritos | completo, EN + ES, todos `draft`     |
| [`loyalty`](/es/modules/loyalty/overview)     | [prd](/es/modules/loyalty/prd)   | [spec](/es/modules/loyalty/spec)   | 14 escritos | completo, EN + ES, en `review` 0.2.0 |
| [`messaging`](/es/modules/messaging/overview) | [prd](/es/modules/messaging/prd) | [spec](/es/modules/messaging/spec) | 9 escritos  | completo, EN + ES, todos `draft`     |
| [`crm`](/es/modules/crm/overview)             | [prd](/es/modules/crm/prd)       | [spec](/es/modules/crm/spec)       | 5 escritos  | completo, EN + ES, todos `draft`     |

## 11. Cuándo podar esto

Si en unos meses se están escribiendo specs que nadie lee, el sistema falló y hay que recortarlo en vez
de defenderlo. La señal honesta: un FS cuyos criterios de aceptación nunca se contrastaron contra el
código mergeado. La ceremonia solo vale su costo porque un agente con un spec aprobado y criterios de
aceptación reales produce trabajo mucho más consistente que uno con un prompt — si eso deja de ser
cierto, hay que dejar de pagarla.
