---
name: nemesis-evaluacion-json
description: >
  Schema y protocolo de emisión del archivo evaluacion.json que el agente
  nemesis-auditor-swl produce al final de cada iteración del loop
  evaluator-optimizer. Estructura PASS/NEEDS_IMPROVEMENT/FAIL + hallazgos
  por archivo:línea + feedback estructurado consumible por orquestador-swl.
  Cargar cuando el agente nemesis necesita emitir output estructurado para
  alimentar el ciclo de remediación de /swl:nemesis --remediar, o cuando
  un componente downstream necesita parsear el veredicto de una auditoría
  nemesis.
version: "1.0.0"
exclusiones:
  - "No cargar para schemas de otros tipos de auditoría (revisor-codigo, revisor-seguridad) — cada uno tiene su propio formato."
  - "No cargar fuera del contexto del agente nemesis-auditor-swl o del comando /swl:nemesis — el schema es específico de esta auditoría."
  - "No cargar para definir nuevos formatos de evaluación — este skill describe el formato existente, no especifica formatos nuevos."
---

# Schema del evaluacion.json del Nemesis

Este skill define el contrato JSON que `nemesis-auditor-swl` emite tras cada
auditoría. El archivo vive en `.planning/audit/findings/iter-N/evaluacion.json`
y es la fuente de verdad estructurada que el comando `/swl:nemesis` consume
para decidir convergencia, activar remediación o escalar al Recovery Catalog.

Junto al JSON se emite también el reporte markdown legible (`nemesis-verified.md`
en el mismo directorio), pero la **decisión automática del loop se toma sobre
el JSON**, no sobre el markdown.

---

## Cuándo cargar

- El agente `nemesis-auditor-swl` está terminando una pasada y necesita
  consolidar hallazgos en formato estructurado.
- El comando `/swl:nemesis` necesita parsear el veredicto para decidir
  PASS / continuar loop / aplicar Recovery.
- Un componente downstream (orquestador-swl, hook de telemetría, dashboard)
  necesita leer auditorías históricas con consistencia.

## Cuándo NO cargar

- Auditoría sin loop (`/swl:nemesis` sin `--remediar`): el JSON sigue
  produciéndose, pero el reporte markdown es suficiente para consumo humano.
- Componentes que solo necesitan el conteo agregado de hallazgos —
  usar `Skill("memoria-busqueda")` sobre los reportes históricos.

---

## Schema canónico (v1.0.0)

```json
{
  "schema_version": "1.0.0",
  "metadata": {
    "iteracion": 1,
    "max_iter": 3,
    "fecha_emision": "2026-05-16T20:30:00Z",
    "scope": {
      "modulos": ["backend/app/auth/", "database/schemas/002-schema-usuario.sql"],
      "loc_total": 627,
      "archivos_analizados": 5
    },
    "modo": "monolitico",
    "agente_emisor": "nemesis-auditor-swl",
    "version_agente": "1.0.0",
    "comando_invocacion": "/swl:nemesis --remediar --modulo backend/app/auth"
  },
  "veredicto": {
    "status": "NEEDS_IMPROVEMENT",
    "score": 78,
    "puede_remediar_automaticamente": true,
    "razon_si_fail": null
  },
  "hallazgos": [
    {
      "id": "F-04",
      "severidad": "ALTA",
      "categoria_owasp": "A07-Identification-and-Authentication-Failures",
      "categoria_a11": "Agencia-excesiva-no-aplica",
      "archivo": "backend/app/auth/service.py",
      "linea_inicio": 191,
      "linea_fin": 243,
      "descripcion": "Backend nunca incrementa intentos_fallidos pese a que el schema declara la columna y constraint CHECK <= 10. Credential stuffing trivial.",
      "evidencia_adicional": {
        "schema_archivo": "database/schemas/002-schema-usuario.sql",
        "schema_linea": "438-451",
        "constraint": "CHECK (intentos_fallidos >= 0 AND intentos_fallidos <= 10)"
      },
      "accion_sugerida": {
        "tipo": "implementar",
        "descripcion": "Crear funcion SQL usuario.fn_registrar_intento_fallido(email) atomica. Llamar tras bcrypt verify fail. Verificar bloqueado=true antes de validar password.",
        "agente_recomendado": "backend-python-swl",
        "skills_recomendados": ["fastapi-experto", "postgresql-experto"],
        "loc_estimado": 60,
        "riesgo_regresion": "BAJO"
      },
      "discovery_path": "Feynman-cross-State",
      "verification": "Code-trace",
      "feedback_para_generator": "El schema ya tiene la columna. NO crear nueva tabla. NO modificar el constraint. Solo agregar la funcion SQL atomica + invocacion desde backend. Mantener la firma de authenticate_user sin cambios externos visibles."
    }
  ],
  "estadisticas": {
    "total_hallazgos": 16,
    "por_severidad": {
      "CRITICA": 0,
      "ALTA": 4,
      "MEDIA": 5,
      "BAJA": 4,
      "INFORMATIVA": 3
    },
    "veto_items": 0,
    "regresiones_detectadas": 0
  },
  "comparacion_iteracion_previa": {
    "hallazgos_cerrados": [],
    "hallazgos_nuevos": ["F-01", "F-02", "F-03", "F-04"],
    "hallazgos_persistentes": [],
    "regresiones_introducidas": []
  },
  "recomendacion_loop": {
    "accion": "remediar",
    "razon": "4 hallazgos ALTOS con accion_sugerida claras y agente_recomendado disponible.",
    "siguiente_iteracion_esperada": "Tras fix de F-01 a F-04, esperar status=PASS si los MEDIOS y BAJOS no son bloqueantes."
  }
}
```

---

## Reglas de emisión

### status del veredicto

El campo `veredicto.status` es la única señal que el comando lee para decidir
convergencia. Reglas estrictas:

- **PASS**: 0 hallazgos críticos + 0 hallazgos altos. Pueden quedar MEDIOS,
  BAJOS o INFORMATIVOS — el usuario decide si los persigue manualmente.
- **NEEDS_IMPROVEMENT**: hay hallazgos ALTOS o CRÍTICOS pero
  `puede_remediar_automaticamente=true` para todos. El loop continúa.
- **FAIL**: al menos un hallazgo crítico o alto requiere intervención humana
  (decisión de producto, cambio arquitectural, datos inválidos). El comando
  escala a Recovery Catalog inmediatamente sin agotar max-iter.

### Veto items

Si el agente detecta veto items (definidos en `reglas/gobernanza.md § Veto items`),
el status DEBE ser FAIL y `puede_remediar_automaticamente=false`. Veto items
nunca son auto-remediables.

### puede_remediar_automaticamente

Un hallazgo es auto-remediable si:

1. La `accion_sugerida` es concreta (no "evaluar opciones").
2. Existe `agente_recomendado` válido en el catálogo SWL.
3. El `riesgo_regresion` es BAJO o MEDIO.
4. El cambio NO requiere decisión arquitectural (no necesita ADR).

Si cualquiera de los 4 falla, marcar `puede_remediar_automaticamente=false`
y dejar el hallazgo para revisión humana.

### Discovery path

Mantener la taxonomía del agente original:

- `Feynman-only`: detectado únicamente por la pasada Feynman.
- `State-only`: detectado únicamente por State Inconsistency.
- `Feynman-cross-State`: hallazgo cruzado entre pasadas (mayor confianza).
- `Cross-feed-Pass-N-M`: hallazgo que emergió tras N pasadas de feedback.

### comparacion_iteracion_previa

OBLIGATORIO en iteraciones >= 2. Permite al comando:

- Detectar **convergencia parcial**: si `hallazgos_cerrados` crece y
  `hallazgos_nuevos` decrece, el loop avanza correctamente.
- Detectar **regresiones**: si `regresiones_introducidas` no está vacío,
  el generator introdujo bugs nuevos al remediar. Activar Recovery.
- Detectar **estancamiento**: si los mismos hallazgos persisten 2 iters
  seguidos sin cerrarse, marcar como FAIL al alcanzar iter 3.

En iteración 1, `comparacion_iteracion_previa.hallazgos_cerrados=[]` y todos
los hallazgos son `hallazgos_nuevos`.

---

## Validación obligatoria antes de emitir

El agente DEBE validar el JSON contra estas reglas antes de escribir el archivo:

1. `schema_version` presente y == "1.0.0" en esta versión del skill.
2. `metadata.iteracion` <= `metadata.max_iter`.
3. Cada hallazgo tiene `id`, `severidad`, `archivo`, `linea_inicio`, `descripcion`, `accion_sugerida`.
4. `archivo` es path relativo al root del proyecto, sin componentes `..`.
5. `linea_inicio` <= `linea_fin` cuando ambos están presentes.
6. `severidad` ∈ {CRITICA, ALTA, MEDIA, BAJA, INFORMATIVA}.
7. `accion_sugerida.agente_recomendado` existe en el manifiesto de agentes
   SWL (verificable con `grep -l "name: <agente>" agentes/`).
8. `puede_remediar_automaticamente` es booleano coherente con `accion_sugerida` y `riesgo_regresion`.

Si la validación falla, el agente emite el JSON con `veredicto.status=FAIL` y
`veredicto.razon_si_fail` documentando el problema de validación. NUNCA emite
JSON malformado al comando.

---

## Pattern de consumo por el comando

```javascript
const evaluacion = JSON.parse(readFileSync('.planning/audit/findings/iter-' + N + '/evaluacion.json'));

if (evaluacion.veredicto.status === 'PASS') {
    return { exito: true, iters: N };
}

if (evaluacion.veredicto.status === 'FAIL') {
    return activarRecoveryCatalog('escalate', evaluacion.veredicto.razon_si_fail);
}

if (!evaluacion.veredicto.puede_remediar_automaticamente) {
    return activarRecoveryCatalog('escalate', 'Hallazgos no auto-remediables');
}

const hallazgosRemediables = evaluacion.hallazgos.filter(h => h.severidad === 'CRITICA' || h.severidad === 'ALTA');
invocar('orquestador-swl', { hallazgos: hallazgosRemediables, feedback: evaluacion });
```

---

## Versionado del schema

`schema_version` semver. Cambios:

- **PATCH** (1.0.X): clarificaciones, campos opcionales agregados, ejemplos.
- **MINOR** (1.X.0): campos nuevos opcionales que el comando puede ignorar.
- **MAJOR** (X.0.0): cambios incompatibles — el comando DEBE rechazar JSONs
  de versiones mayores no soportadas con error explícito.

Cualquier cambio MAJOR del schema requiere ADR propio referenciando ADR-0021.

---

## Anti-patrones

- **Emitir JSON sin `status`**: el comando no sabe qué hacer y aplica Recovery
  de forma defensiva. Caro y confuso.
- **Inventar `agente_recomendado` no existente** en el catálogo SWL: el
  orquestador no puede delegar y el loop falla en iter 1. Validar con grep.
- **Marcar todo como `puede_remediar_automaticamente=true`** sin verificar
  riesgo de regresión: el loop introduce bugs por confianza excesiva.
- **Omitir `comparacion_iteracion_previa` en iter >= 2**: el comando no puede
  detectar regresiones ni estancamiento y aplica solo el guardrail de max-iter
  (peor experiencia).
- **Mezclar veredicto y feedback en el mismo string**: el `status` debe ser
  enum estricto. El feedback descriptivo va en `feedback_para_generator` por
  hallazgo, no en el status.

---

## Referencias

- ADR-0021: `nemesis-evaluator-optimizer`.
- `reglas/gobernanza.md § Veto items y cap enforcement`: define qué constituye
  veto y por qué fuerza FAIL.
- `reglas/seguridad-agentes.md § Recovery Catalog`: define qué hacer cuando
  status=FAIL o cuando max-iter se agota.
- Cookbook Anthropic, patrón evaluator-optimizer: el campo `status` es
  equivalente al `evaluation` XML del cookbook; `feedback_para_generator` al
  `feedback` XML.
