# Workflow reference — Business Rules Catalog

Cómo crear, derogar y modificar reglas. Para el formato exacto del `.md`, ver `format.md`.

> Tres workflows independientes (A, B, C) más temas operativos (cross-aggregate, asunciones,
> citas `@rule`). La nomenclatura coincide con `docs/business-rules/README.md`.

---

## Workflow A — Vía OpenSpec (recomendado para cambios planificados)

Aplicable cuando el cambio pasa por OpenSpec (`propose → apply → archive → promote`). El
comando `/business-rules:promote` maneja **todas las acciones** declaradas en el `proposal.md`
en una sola pasada.

```
┌───────────────────────────────────────────────────────────────────────────┐
│  1. /opsx:propose <descripción>                                           │
│     - El config.yaml inyecta instrucciones de business-rules.            │
│     - Claude consulta cliter/<bc>/business-rules/* relevantes.            │
│     - Si detecta conflicto, presenta opciones al user (a/b/c).            │
│     - Genera proposal.md con sección "Business rules affected".           │
│  2. (Si hay conflicto) Tú resuelves; Claude registra la decisión.         │
│  3. /opsx:apply — Claude implementa el código.                            │
│  4. /opsx:archive <name> — cierra el ciclo, mueve a archive/.             │
│  5. /business-rules:promote — coordina dos sub-pasos:                     │
│       5.a Script :promote (Node):                                         │
│           - Para `mantiene BR-X`: no-op.                                  │
│           - Para `deroga BR-Y`: state→derogated + sección ###Derogación.  │
│           - Para `extiende BR-Z`: no-op del script (recordatorio manual). │
│           - Para `Nuevas`: scaffold con ID secuencial real, state=        │
│             proposed, body con [VERIFICAR].                               │
│           Regenera índice.                                                │
│       5.b Claude (continuación, misma sesión):                            │
│           Para cada regla creada en 5.a:                                  │
│           - Lee proposal.md archivado, código del agregado, tests,        │
│             CONTEXT.md.                                                   │
│           - Redacta body real (Enunciado, Casos, Implementa, Tests,       │
│             Diagrama de cascada si aplica).                               │
│           - Pide confirmación al usuario.                                 │
│           - Sustituye [VERIFICAR] por contenido real.                     │
│           - Cambia state=proposed → state=active.                         │
│           pnpm br:generate && pnpm br:validate (o pre-commit hook).       │
└───────────────────────────────────────────────────────────────────────────┘
```

### Sección "Business rules affected" en proposal.md

Estructura mínima:

```markdown
## Business rules affected

### Existentes
- mantiene BR-PROD-EVENT-005 — descripción breve.
- deroga BR-PROD-EVENT-003 — razón breve.
- extiende BR-PROD-HEADER-001 — relación.

### Nuevas
- en `production-planning/production-order-position-event` — Validación de cancelación.
- BR-PROD-EVENT en `production-planning/production-order-position-event` — Validación de cancelación.
  (forma con prefijo de ID explícito; necesaria solo si el archivo destino no tiene reglas previas
  de las que el script pueda inferir el prefijo)
```

Si no hay reglas afectadas: escribir `None` bajo la sección.

### Asignación de IDs en reglas nuevas

`:promote` lee el path del proposal y asigna el siguiente número secuencial. Para el prefijo:

- **Inferencia automática**: si el archivo destino ya tiene reglas, el script toma el prefijo
  más común (en la práctica, el del último spec/regla creada en ese archivo). Ejemplo: si las
  reglas existentes son `BR-PROD-EVENT-001` y `BR-PROD-EVENT-002`, la nueva será
  `BR-PROD-EVENT-003`.
- **Prefijo explícito**: si el archivo está vacío, el proposal lo declara como
  `- BR-PROD-EVENT en \`...\` — Título`. Por convención, el explícito debe coincidir con el
  prefijo del último spec creado en agregados similares del mismo bounded context.

### Estado del índice tras el flujo

- Tras 5.a el script ya regeneró el índice automáticamente.
- En 5.b Claude edita los `.md` (sustituye `[VERIFICAR]`, cambia `proposed` → `active`), por lo
  que el índice se desactualiza.
- Antes del commit hay que regenerar otra vez. La pre-commit hook lo hace automáticamente al
  detectar cambios staged en el catálogo.

---

## Workflow B — Documentación retroactiva (vía `/business-rules:document`)

Aplicable cuando:

- El catálogo no cubre un agregado y quieres extraer reglas implícitas de código existente.
- Un bug destapa una regla no documentada.
- Tienes un Word funcional con reglas que quieres formalizar.

```
/business-rules:document <bc>/<aggregate>
   o
/business-rules:document <bc>/<aggregate> --from path/to/word-export.md
```

El script:

1. Verifica que el agregado existe (busca `cliter/<bc>/<aggregate>.aurora.yaml`).
2. Crea el archivo del catálogo con frontmatter scaffold (si no existe).
3. Lista las fuentes que el LLM debe consultar (YAML, CONTEXT.md, código, tests).
4. Imprime guidance para que el LLM identifique reglas implícitas.

Después, el LLM (en sesión interactiva) sigue:

1. Lee YAML del agregado → estados, relaciones, campos.
2. Lee CONTEXT.md → flujo del BC.
3. Recorre los archivos de dominio listados.
4. Identifica reglas (precondiciones, cascadas, invariantes derivados, políticas).
5. Para cada regla detectada:
   - Asigna ID nuevo siguiendo el prefijo del último spec creado del agregado.
   - Redacta enunciado en español.
   - Construye tabla exhaustiva de casos. Marca `[VERIFICAR]` solo en filas concretas que no
     pueda derivar claramente del código (NO en headers de secciones — el body es real).
   - Cita paths reales en `Implementa` y `Tests`.
6. **Pide confirmación al usuario** antes de escribir cada regla.
7. Persiste y valida:
   ```
   pnpm br:generate && pnpm br:validate
   ```

Estado típico: `active` (la regla ya está implementada porque la deduces del código). Excepción:
`proposed` cuando documentas una intención que el código no satisface todavía (ver "Gap
producto↔código" más abajo).

### Importar Word funcional con `--from`

Cuando hay material externo:

- Tratarlo como **candidato**, no autoritativo.
- Verificar cada regla candidata contra el código real.
- En cada divergencia, marcar `[VERIFICAR]` y resolver con producto/dominio.

### Limitación

Este workflow **solo crea** reglas nuevas. Para derogar o modificar reglas existentes, usa el
Workflow C.

---

## Workflow C — Edición directa

Aplicable cuando ni OpenSpec ni `:document` aplican: fixes ad-hoc, ajustes sin cambio
semántico, derogations puntuales fuera de OpenSpec, modificaciones manuales del catálogo.

### C.1 — Crear una regla nueva

Editar el `.md` del agregado a mano:

1. Asignar un ID nuevo siguiendo el prefijo del último spec creado del agregado (no reusar
   derogados).
2. Pegar la plantilla canónica (ver `format.md`).
3. Rellenar enunciado, tabla de casos, `Implementa`, `Tests`.
4. Marcar `[VERIFICAR]` o `[ASUNCIÓN]` solo en casos concretos que dudes.
5. `pnpm br:generate && pnpm br:validate` (o lo hace la pre-commit hook al commitear).

### C.2 — Derogar una regla

Las reglas **no se editan en su semántica**. Para retirar o reemplazar una regla:

```
1. Localizar la regla:
   pnpm br:check BR-PROD-EVENT-005

2. En el archivo, abrir la regla y modificar la metadata:
     | Estado | `derogated`                                          |
     | Origen | retro-documentada (derogada por BR-PROD-EVENT-007)   |

3. Añadir sección "### Derogación" al final del cuerpo:
     ### Derogación
     Derogada el 2026-06-15 por **BR-PROD-EVENT-007**.
     Razón: <motivo en una frase>.

4. (Si hay regla sustituta) crearla con un ID nuevo (no reusar 005):
     ## BR-PROD-EVENT-007 — <Nuevo título>
     ...
     ### Reglas relacionadas
     - BR-PROD-EVENT-005 (derogada por esta regla).

5. Regenerar:
   pnpm br:generate && pnpm br:validate
   (o lo hace la pre-commit hook al commitear)

6. Commit:
   chore(business-rules): derogate BR-PROD-EVENT-005, add BR-PROD-EVENT-007
```

### C.3 — Modificar una regla (= derogar + crear)

Modificar la semántica de una regla equivale a derogar la antigua y crear una nueva con ID
nuevo. Sigue C.2 + C.1.

#### Edits permitidos en sitio sin derogar (no son cambios semánticos)

- Corregir typos, gramática, formato.
- Reformular frases sin alterar significado.
- Arreglar paths rotos en `Implementa` / `Tests`.
- Refrescar `last_updated` tras cualquier cambio.
- Resolver `[VERIFICAR]` o `[ASUNCIÓN]` sustituyendo por contenido validado.
- Añadir filas a la tabla de casos (cubrir más espacio sin contradecir lo ya cubierto).

#### Cambios que requieren derogación obligatoria

- Cambiar resultado de un caso ya enumerado.
- Cambiar enunciado en su significado.
- Cambiar severidad (`blocking` ↔ `informational`).

> **No se borra la regla derogada en ningún workflow**. Permanece visible para que las
> citaciones históricas en código y commits sigan siendo unívocas.

---

## Temas operativos (transversales a los workflows)

### Reglas cross-aggregate y cross-BC

#### Decidir dónde vive la regla

La regla **vive en un único archivo**: el del agregado donde se observa el invariante final.

```
Cascada delete(event) → position PENDING → header PENDING + startDate=null
                                                              ↑
                                                  invariante final
                                                  (vive aquí)
```

→ Vive en `cliter/production-planning/business-rules/production-order-header.md`.

#### Apuntadores

Los archivos de los demás agregados/BCs llevan apuntadores cortos. Plantillas en `format.md`.

#### Frontmatter en plural

```yaml
bounded_contexts:
  - production-planning
  - iam                    # si la regla es cross-BC
aggregates:
  - production-planning/production-order-header
  - production-planning/production-order-position
  - production-planning/production-order-position-event
  - iam/role               # si afecta a un agregado de iam
```

Esto permite que el filtrado por BC en la detección de conflictos retorne la regla
automáticamente desde cualquiera de los BCs declarados.

### Resolver `[VERIFICAR]` y `[ASUNCIÓN]`

Cuando una regla tiene una celda con `**[VERIFICAR caso 4]**` u otro caso del que no estás
seguro:

1. **Pregunta a producto/dominio** la pregunta concreta.
2. Edita la regla en sitio:
   - Sustituye `**[VERIFICAR caso 4]**` en la celda por el valor confirmado.
   - Borra (o resume) la entrada en la sección "Asunciones a verificar".
3. Refresca `last_updated`.
4. `pnpm br:generate && pnpm br:validate` (o lo hace la pre-commit hook al commitear).

Esto es **edit en sitio sin derogar** (es un sub-caso del Workflow C): rellenar un caso
`[VERIFICAR]` no cambia el significado de la regla, solo cierra una laguna.

### Gap producto↔código (estado `proposed` legítimo en el catálogo)

Es legítimo dejar una regla en `Estado: proposed` y commitearla cuando documentas una intención
que el código no satisface todavía y quieres que el gap sea visible y auditable.

Ejemplo: `BR-PROD-HEADER-002` describe la cascada de revert al borrar el último evento;
producto la quiere pero el código no la implementa. Marcarla como `proposed` hace el gap
explícito y trazable.

NO es legítimo dejar `proposed` con `[VERIFICAR]` en headers como resultado de una sesión
interrumpida del Workflow A (sub-paso 5.b). Si ves uno, completa el body antes de commitear.

### Citas `@rule` en código (opcional)

```typescript
/**
 * Cancela un evento de producción.
 *
 * @rule BR-PROD-EVENT-001 — No cancelar eventos DONE
 * @see cliter/production-planning/business-rules/production-order-position-event.md
 */
async cancel(eventId: string): Promise<void> {
  ...
}
```

- Es **opcional**, no enforcement.
- Mejora la legibilidad para futuros lectores.
- El audit reporta orphans (`@rule` sin entry en catálogo) y zombies (regla activa sin ningún
  `@rule` tras 30 días). Ambos son advisory; no bloquean builds.
