---
name: swl:nemesis
description: >
  Auditoría iterativa Feynman + State Inconsistency con loop evaluator-optimizer
  opcional. Sin flag --remediar: solo audita (comportamiento clásico de
  v1.5.x). Con --remediar: ciclo audit→fix→re-audit hasta convergencia
  (max 3 iteraciones, Recovery Catalog si no converge). Modo redistribuido
  automático para scope > 1500 LOC o > 5 archivos en módulos distintos.
  Persiste hallazgos en .planning/audit/findings/iter-N/.
allowed-tools: [Read, Grep, Glob, Bash, Write, Agent, Skill]
argument-hint: "[--remediar] [--pass1 | --pass2 | --continue] [--modulo <ruta>] [--redistribuir] [--reset-plan] [--cross-model]"
---

# /swl:nemesis — Auditoría iterativa con remediación opt-in

Dos auditores en loop interno (Feynman + State Inconsistency) detectan bugs de
profundidad que el código superficialmente correcto esconde. Con el flag
`--remediar` el comando entra en modo **evaluator-optimizer** (patrón oficial
de Anthropic, ADR-0021): el agente nemesis evalúa, el orquestador-swl remedia,
y el ciclo continúa hasta convergencia o agotar el guardrail de 3 iteraciones.

## Cuándo invocar

- El módulo pasó `/swl:revisar` con score ≥ 9.0 pero hay sospechas de bugs
  de lógica profunda que el revisor de código no captura (suposiciones
  incorrectas, invariantes rotos, condiciones de carrera sutiles).
- Antes de un release de componente crítico: auth, pagos, contratos, permisos.
- Cuando un bug en producción se atribuye a lógica aparentemente correcta —
  usar Nemesis para encontrar el patrón de fallo subyacente.
- Para módulos legacy con alta deuda técnica donde los tests no cubren los
  caminos de estado.
- **Para cerrar el loop audit→fix→re-audit en una sola invocación**: usar
  `/swl:nemesis --remediar`. La autonomía es opt-in.

## Cuándo NO invocar

- El módulo tiene menos de 200 LOC y es CRUD simple sin lógica de negocio.
- Se necesita revisión de estilo, naming o cobertura de tests — usar
  `/swl:revisar` en su lugar.
- El proyecto no tiene `agentes/nemesis-auditor-swl.md` instalado — verificar
  con `ls agentes/ | grep nemesis` antes de invocar.
- La tarea urgente es un hotfix en producción — Nemesis con `--remediar` es
  deliberado (8-30 turnos); en incidente activo, usar `/swl:verificar` acotado.

## Modos disponibles

| Modo | Flag | Descripción |
|---|---|---|
| **Solo auditar** (default) | (sin flag) | Pasada 1 (Feynman) + Pasada 2 (State) + N alternadas hasta convergencia interna, máximo 6 pasadas. Entrega reporte. NO remedia. Retrocompatible con v1.5.x. |
| **Loop completo** | `--remediar` | Evaluator-optimizer: audita → invoca `orquestador-swl` con hallazgos → re-audita. Max 3 iteraciones. Convergencia cuando status=PASS. Recovery Catalog si no converge. |
| Solo Feynman | `--pass1` | Una pasada Feynman exhaustiva; no ejecuta State. Ortogonal a `--remediar`. |
| Solo State | `--pass2` | Una pasada State Inconsistency; puede alimentarse con findings previos. |
| Retomar | `--continue` | Continúa desde la última iteración registrada en `.planning/audit/findings/`. |
| Acotar módulo | `--modulo <ruta>` | Limita el scope a un archivo o subdirectorio específico. Se combina con cualquier otro flag. |
| Forzar redistribución | `--redistribuir` | Activa `Skill("nemesis-redistribuir")` aunque scope sea menor al umbral. |
| Reset del plan | `--reset-plan` | Regenera `nemesis-plan.json` desde cero (descarta plan previo). |
| **Revisión cross-modelo** | `--cross-model` | Opt-in: rutea la evaluación a un reviewer en OTRO modelo (vía MCP, p.ej. `gemini-review`/`codex-review`) para combatir *self-preferential bias*. Degrada al reviewer same-model si no hay MCP configurado (anuncia la degradación). Combina con `--remediar`. Ver `Skill("proceso-dynamic-workflows") § Revisión cross-modelo`. |

## Revisión cross-modelo (`--cross-model`)

El reviewer adversarial en el MISMO modelo aún arrastra *self-preferential bias*
(uno de los 3 modos de falla nombrados en el blog oficial de dynamic workflows).
`--cross-model` hace que la evaluación la emita un modelo DISTINTO al ejecutor:

- **Wiring (opt-in, ligero)**: si hay un MCP reviewer configurado (patrón ARIS
  `gemini-review`/`codex-review`: expone `review`/`review_reply`, devuelve JSON con
  `threadId` + `response`), el paso de evaluación se rutea a ese MCP. swl-ses NO
  embebe el servidor — lo provee el usuario con su API key del otro modelo.
- **Degradación explícita** (regla `arreglar-al-detectar.md` / no-fallback-silencioso):
  si el MCP no está disponible, NO falla — usa el reviewer same-model y **anuncia**
  "cross-model solicitado pero MCP ausente → degradado a same-model".
- **Reviewer memory + debate** (de ARIS `auto-review-loop`): el reviewer externo
  arrastra sospechas entre iteraciones (un `threadId`); el ejecutor puede rebatir,
  el reviewer falla el veredicto final — *"it can drive, never acquit"*.
- **Trazabilidad**: el JSON del reviewer (`threadId`, `response`, score) se persiste
  junto a `evaluacion.json` en `.planning/audit/findings/iter-N/` → veredicto
  independiente auditable.

Detalle del patrón: `Skill("proceso-dynamic-workflows") § Revisión cross-modelo`.

## Flujo completo con `--remediar`

```
# iter usa indexing 1-based para alinear con el agente y los output paths
# (.planning/audit/findings/iter-1/, iter-2/, iter-3/). Max 3 iteraciones.
iter = 1
MAX_ITER = 3
evaluacion = null

# Fase 0 del comando: análisis del scope
loc_total, modulos = analizar_scope(modulo_arg or "directorio actual")

# Decisión de redistribuir:
#   1. --redistribuir explícito siempre activa redistribución (override del usuario).
#   2. --modulo respeta el scope acotado por el usuario y NO redistribuye, aunque
#      excede umbrales. El usuario ya delimitó intencionalmente.
#   3. Sin --modulo: umbrales automáticos (> 1500 LOC ó > 5 módulos distintos).
redistribuir = flag_redistribuir or (
    not flag_modulo and (loc_total > 1500 or modulos > 5)
)

if redistribuir:
    cargar Skill("nemesis-redistribuir")
    plan = generar_plan_redistribuido(scope)
    persistir plan en .planning/audit/nemesis-plan.json
    sub_scopes = plan.sub_scopes
else:
    sub_scopes = [scope_unico]

# Fase 1+: loop evaluator-optimizer (iter ∈ {1, 2, 3})
while iter <= MAX_ITER:
    # Evaluator: invocar nemesis-auditor-swl una vez por sub-scope.
    # En modo redistribuido cada sub_scope tiene un `id` (declarado en
    # nemesis-plan.json) que el agente USA para construir la ruta de output
    # `.planning/audit/findings/iter-N/<sub_id>/`. Sin sub_id, los reportes
    # se sobrescribirían entre sub-scopes. En modo monolítico sub_id queda
    # `null` y el agente escribe a `iter-N/` (sin subdirectorio).
    for sub_scope in sub_scopes:
        sub_id = sub_scope.id if redistribuir else null
        invocar(nemesis-auditor-swl, sub_scope, iter=iter, sub_id=sub_id)
        # Produce:
        #   redistribuido → .planning/audit/findings/iter-N/<sub_id>/evaluacion.json + .md
        #   monolítico    → .planning/audit/findings/iter-N/evaluacion.json + .md

    # Consolidar (si modo redistribuido)
    evaluacion = consolidar_evaluaciones(iter)
    # Produce: .planning/audit/findings/iter-N/evaluacion.json consolidado
    # (en modo monolítico no hay consolidación: el archivo ya está en iter-N/)

    # Decisión sobre el JSON consolidado
    if evaluacion.veredicto.status == "PASS":
        emitir_reporte_final(evaluacion)
        return { exito: True, iters: iter, evaluacion }   # convergencia

    if not flag_remediar:
        emitir_reporte(evaluacion)
        return { exito: False, iters: iter, evaluacion }  # solo audita

    if evaluacion.veredicto.status == "FAIL":
        return activar_recovery_catalog("escalate", evaluacion.veredicto.razon_si_fail)

    if not evaluacion.veredicto.puede_remediar_automaticamente:
        return activar_recovery_catalog("escalate", "Hallazgos no auto-remediables")

    # Generator: invocar orquestador-swl con hallazgos como input
    invocar(
        orquestador-swl,
        hallazgos=evaluacion.hallazgos,
        feedback=evaluacion,
        intentos_previos=hallazgos_de_iters_anteriores(iter),
        iter=iter,
    )
    iter += 1

# max-iter agotado sin PASS
return activar_recovery_catalog_secuencial(evaluacion)
# orden: reprompt(1ª) → reduce-autonomy(2ª) → escalate(3ª)
```

Los `return` son explícitos. Sin `--remediar`, el `return` del bloque
`if not flag_remediar` impide que el flujo alcance la invocación del
orquestador. La retrocompatibilidad es por construcción.

## Activación de redistribución (Fase 0)

| Condición | Acción |
|---|---|
| `loc_total > 1500` | Cargar `Skill("nemesis-redistribuir")` |
| `archivos_modulos_distintos > 5` | Cargar `Skill("nemesis-redistribuir")` |
| `--redistribuir` explícito | Cargar `Skill("nemesis-redistribuir")` |
| `--modulo <ruta>` con scope acotado | NO redistribuir (respetar decisión explícita del usuario) |

Cuando se activa, el comando registra un nudge en `.planning/nudges.jsonl`:

```json
{
  "timestamp": "<ISO 8601>",
  "tipo": "nemesis-redistribuido",
  "mutation_category": "scope-adaptation",
  "risk_level": "low",
  "razon": "loc_total=3170 (>1500)",
  "sub_scopes": 3,
  "archivo_plan": ".planning/audit/nemesis-plan.json"
}
```

## Recovery Catalog cuando max-iter sin PASS

Tras 3 iteraciones del loop sin alcanzar `status=PASS`, el comando aplica en
orden estricto el catálogo de `reglas/seguridad-agentes.md § Recovery Catalog`:

1. **reprompt** (excedencia 1): re-invoca al orquestador con feedback reforzado
   (qué hallazgos quedaron sin resolver, constraints adicionales). Una sola vez.
2. **reduce-autonomy** (excedencia 2 consecutiva): baja `nivelRiesgo` efectivo,
   pide confirmación al usuario antes de cada acción del generator.
3. **escalate** (excedencia 3): pausa la cadena, invoca `notificador-swl`,
   espera decisión humana del usuario.
4. **terminate**: solo si el evaluator detecta violación de regla de seguridad
   explícita (no por simple no-convergencia).

Cada activación se registra en `.planning/nudges.jsonl` con
`mutation_category: repair` y `risk_level` proporcional.

## Qué produce

Estructura de salida bajo `.planning/audit/findings/`:

```
.planning/audit/findings/
├── nemesis-plan.json                     # solo si modo redistribuido
├── iter-1/
│   ├── feynman-pass1.md                  # output crudo Feynman
│   ├── feynman-pass2.md                  # si hubo segunda pasada Feynman
│   ├── state-pass1.md                    # output crudo State
│   ├── state-pass2.md                    # si hubo segunda pasada State
│   ├── nemesis-verified.md               # reporte legible consolidado
│   ├── evaluacion.json                   # veredicto estructurado
│   ├── sub-1/                            # solo en modo redistribuido
│   │   ├── feynman-pass1.md
│   │   ├── state-pass1.md
│   │   ├── nemesis-verified.md
│   │   └── evaluacion.json
│   ├── sub-2/
│   └── sub-3/
├── iter-2/                               # solo si --remediar y no convergió en iter 1
│   └── (mismo formato)
└── iter-3/                               # último intento si --remediar y no convergió
    └── (mismo formato)
```

Cada `evaluacion.json` sigue el schema `nemesis-evaluacion-json` v1.0.0.

### Telemetría de loop (obligatoria con `--remediar`)

En modo `--remediar`, además de los `iter-N/` el comando registra la
trayectoria en el formato estándar de telemetría de loops
(`hooks/lib/loop-telemetry.js`). Esto habilita: inyección de estado por el
hook `contexto-iteracion.js` durante las ejecuciones largas (8-30 turnos),
detección de plateau, y lectura de la corrida por `/swl:status metricas`.

- Al iniciar iter-1: `iniciarCorrida({tipo: 'nemesis', direccion: 'lower_is_better', config: {modulo, maxIter: 3}})`.
- Tras cada iteración: `registrarIteracion(dir, {iteracion: N, metrica: criticos+altos, delta, estado: 'keep', descripcion: 'iter N: status=<status>, X criticos, Y altos'})`.
- Al cerrar (PASS, FAIL o Recovery Catalog): `escribirHandoff(dir, {source: 'swl:nemesis', status, findings: <hallazgos residuales con archivo_linea>, config})`.
  Mapeo de status: PASS → `COMPLETO`, max iteraciones → `ACOTADO`, Recovery
  Catalog/escalada → `INTERRUMPIDO`.

El `handoff.json` resultante es consumible por una corrida posterior de
`/swl:verificar --until-converge` o por el orquestador (los `findings`
traen `archivo_linea` verificable según `verificar-citas-normativas.md § Familia 2`).

## Cómo interpretar el reporte

### Severidades

| Nivel | Criterio |
|---|---|
| CRÍTICO | Explotable sin precondiciones; pérdida de datos o control total |
| ALTO | Explotable bajo condiciones razonables; impacto severo |
| MEDIO | Requiere condiciones específicas; impacto moderado |
| BAJO | Impacto menor o difícil de explotar; documentar para trazabilidad |

### Discovery path

- `Feynman-only`: Feynman lo detectó; State no lo confirmó ni refutó.
- `State-only`: State Inconsistency lo encontró analizando mutaciones.
- `Cross-feed Pass N → Pass M`: Feynman marcó un sospechoso en la pasada N;
  State lo confirmó como bug real en la pasada M (o viceversa). Estos
  hallazgos son los más confiables.

### Veredicto JSON

Los tres status del JSON estructurado del evaluator (definidos canónicamente
en `agentes/nemesis-auditor-swl.md § Veredicto status`):

- **`status: "PASS"`** — convergencia. 0 críticos + 0 altos. Pueden quedar
  hallazgos MEDIOS/BAJOS/informativos. El loop termina con éxito.

- **`status: "NEEDS_IMPROVEMENT"`** — hay críticos o altos pero **todos** tienen
  `accion_sugerida` concreta + `agente_recomendado` válido. El comando con
  `--remediar` invoca al `orquestador-swl` automáticamente. Sin `--remediar`,
  el reporte queda como acción pendiente para el usuario.

- **`status: "FAIL"`** — hay al menos un hallazgo que cumple cualquiera de:
  - Veto items según `reglas/gobernanza.md § Veto items`.
  - Cambio arquitectural ambiguo (requiere ADR / decisión del usuario).
  - Decisión de producto (comportamiento esperado no definido).
  - Datos de entrada inválidos en el alcance auditado.

  El loop se detiene de inmediato y escala a Recovery Catalog. Origen del
  refuerzo: SIGAF sesión 2026-05-21 (alineación L2 — el comando y el agente
  deben tener idéntico criterio de FAIL para evitar loops vacíos).

**Regla de consistencia**: si esta sección del comando y la del agente
diverge en wording, el agente es la fuente de verdad operacional (lo
implementa). Actualizar el comando para alinear, NO al revés.

## Costo estimado

| Modo | Turnos aproximados |
|---|---|
| Solo auditar, módulo pequeño (< 500 LOC) | 8-12 |
| Solo auditar, módulo mediano (500-1500 LOC) | 12-18 |
| Solo auditar, módulo grande (> 1500 LOC, modo redistribuido) | 18-30 |
| `--remediar`, módulo pequeño, converge en 1 iter | 12-18 |
| `--remediar`, módulo mediano, 2-3 iters | 20-40 |
| `--remediar`, módulo grande con redistribución, 3 iters | 40-70 |
| Solo `--pass1` o `--pass2` | 4-8 |

El costo del modo `--remediar` es 3-5× el del modo solo auditar. Es opt-in
deliberado del usuario, no default.

### Calibración para módulos pequeños con alta densidad de control de flujo

Aunque la tabla estima 12-18 turnos para `--remediar` sobre módulo pequeño
(< 500 LOC), el valor agregado es desproporcionadamente alto cuando el
módulo concentra **lógica de control de flujo** (event handlers,
callbacks, `setTimeout`/`setInterval`, readline, promises, race conditions).
La densidad de bugs latentes en este tipo de código es alta, y nemesis los
detecta donde la revisión one-shot no.

**Patrón confirmado en swl-ses v1.6.0** (sesión 2026-05-16): `--remediar`
sobre `scripts/lib/ui.js` (~300 LOC con spinner + readline + prompts)
convergió en iter-2 con 15 turnos totales. Iter-1 detectó dos hallazgos
adicionales que el fix manual no había detectado:

- **F-1 (ALTO)**: listener leak de `process.once('exit')` acumulándose
  en loops que crean N spinners secuenciales → MaxListenersExceededWarning.
- **F-2 (MEDIO)**: `preguntarOpcion` llamaba `_pausarSpinnersActivos()`
  DESPUÉS del primer `console.log` del menú, dejando una ventana donde
  el tick del spinner sobrescribía la primera línea.

Iter-2 confirmó PASS tras aplicar ambos fixes. Ninguno habría sido
detectado por `/swl:revisar` o `revisor-codigo-swl` solos — ambos
requirieron el reasoning iterativo Feynman+State.

**Regla operativa**: tras commits de fix-only en módulos con alta densidad
de control de flujo (no en módulos CRUD puros), correr `--remediar`
acotado al módulo. La inversión de 15 turnos típicamente detecta 1-2
bugs adyacentes que el fix original no cubrió.

## Ejemplos de invocación

```bash
# Modo clásico (retrocompatibilidad v1.5.x): solo audita
/swl:nemesis
/swl:nemesis --modulo backend/app/auth

# Solo una pasada específica
/swl:nemesis --pass1 --modulo backend/app/auth
/swl:nemesis --pass2

# Retomar auditoría interrumpida
/swl:nemesis --continue

# Modo evaluator-optimizer completo (nuevo en v1.5.2)
/swl:nemesis --remediar --modulo backend/app/auth
/swl:nemesis --remediar                              # scope = directorio actual
/swl:nemesis --remediar --modulo database/schemas    # módulo grande → activa redistribución

# Forzar redistribución aunque scope sea pequeño
/swl:nemesis --redistribuir --modulo backend/app/auth
```

## Inyectar foco adicional durante el loop con `SendMessage`

Durante una ejecución `--remediar` larga (8-30 turnos en módulos grandes), el
usuario humano puede observar que el evaluator está siguiendo una pista débil
o ignorando una sospecha concreta. **No es necesario abortar el comando** —
usar `SendMessage` para inyectar foco adicional al agente en curso sin perder
el progreso del loop.

Patrón validado (origen: SIGAF sesión 2026-05-21, mejora D1):

```
# El usuario ve en el chat que la iteración 2 está auditando solo
# permisos y olvida revisar el invariante de auditoría.
# SendMessage al agente activo:

SendMessage({
  to: "nemesis-auditor-swl",   // o el nombre asignado del agente activo
  message: "Antes de cerrar iteración 2: revisa también el invariante de
            auditoría inmutable en module/audit/handlers.py. Sospecho que
            handle_revoke() escribe a la tabla aprobaciones_historial sin
            verificar que el VBO original siga vigente."
});
```

El agente recibe el mensaje en su próximo turno y lo trata como instrucción
adicional sin reiniciar el loop. El registro `audit/findings/iter-N/` queda
intacto.

**Cuándo aplicar**:

- El loop lleva ≥2 iteraciones y el reporte sugiere que olvida un patrón obvio
  para el contexto del módulo.
- Se detecta que el evaluator está dando vueltas sobre el mismo hallazgo de
  baja severidad y conviene priorizar otra zona del código.
- El usuario tiene contexto adicional (incidente reciente, decisión de ADR
  no documentado en CLAUDE.md) que el agente no puede inferir solo.

**Cuándo NO aplicar**:

- La iteración actual está progresando bien — no interrumpir loops que
  convergen.
- El cambio que se quiere inyectar es de scope (cambiar `--modulo`): ahí sí
  abortar con Ctrl+C, reset con `--reset-plan` y re-invocar.
- Inyectar instrucciones contradictorias con el plan congelado del loop —
  viola regla `seguridad-agentes.md § Anti-proxy-goal-drift`.

## Regla obligatoria sobre las citas archivo:línea del reporte

Cuando se actúe sobre un hallazgo `archivo:linea` reportado por el evaluator,
**verificar la cita** con `Read` antes de aplicar el fix. Esto es directiva de
la regla global `verificar-citas-normativas.md` Familia 2 — citas
archivo:línea en reportes de auditoría DEBEN re-verificarse contra el código
actual antes de tomar acción. El loop de remediación NO sustituye esta
verificación — el generator (orquestador-swl + agentes de stack) debe leer el
archivo en su HEAD actual antes de modificar.

## Referencias

- ADR-0021: `nemesis-evaluator-optimizer` — diseño completo del patrón.
- ADR-0018: introducción del agente nemesis-auditor-swl.
- `agentes/nemesis-auditor-swl.md`: agente evaluator.
- `agentes/orquestador-swl.md`: agente generator (delega a depurador, backend-*, frontend-*, etc.).
- `habilidades/nemesis-evaluacion-json/SKILL.md`: schema del JSON estructurado.
- `habilidades/nemesis-redistribuir/SKILL.md`: modo redistribuido para scope grande.
- `reglas/seguridad-agentes.md § Recovery Catalog`: manejo de no-convergencia.
- Cookbook Anthropic, patrón evaluator-optimizer:
  https://github.com/anthropics/anthropic-cookbook/blob/main/patterns/agents/evaluator_optimizer.ipynb

<!-- Adaptado de nemesis-auditor-main bajo MIT License (transmissions11/nemesis-auditor) -->
<!-- Loop evaluator-optimizer agregado en v1.6.0 (ADR-0021), 2026-05-16 -->
