---
name: verificar-trabajo
description: Verificación goal-backward del trabajo ejecutado en 4 niveles progresivos — EXISTE, SUSTANTIVO, CONECTADO, DATOS_FLUYEN. Clasifica claims en 4 tipos (TASK, FIX, TEST_OR_BUILD, FEATURE_GO) con evidencia proporcional. Detecta stubs, componentes huérfanos, integraciones rotas y flujos incompletos. Produce veredictos estructurados JSON con clasificación de riesgo (Low/Medium/High) y evidencia verificable. Soporta loop de reparación cuando el veredicto es Fail.
version: "1.2.1"
evolved: true
evolved-from: "1.2.0"
evolved-at: "2026-05-15"
evolved-by: "aprender"
evolved-note: "Gotchas v1.5.1 acumulados en este ciclo: (1) health-check post-hoc que recalcula contexto del install desde cwd actual → falso positivo (caso doctor 2026-05-15); (2) smoke E2E obligatorio para features cross-cutting (Sub-fase 11.5: transformarAgente nunca invocado pese a suite 100% verde); (3) auto-reparación debe verificar que el chequeo subsecuente ya no detecta el problema, si no → loop infinito (Sub-fase 12: doctor)."
herramientasPermitidas: [Read, Write, Edit, Bash, Glob, Grep]
exclusiones:
  - "No cargar durante la implementación activa de una tarea; la verificación es posterior a la implementación, no concurrente."
  - "No cargar para revisar calidad de código estático (style, naming, SOLID); eso es `checklist-calidad` o el revisor de lenguaje correspondiente."
  - "No cargar para validar que el PLAN.md está bien estructurado antes de ejecutar; eso es parte de `planear-fase`."
  - "No cargar como único mecanismo de QA en producción — es verificación de entregables del plan, no monitoreo de sistemas en vivo."
evolvable: true  # default para skill estandar
---
# Habilidad: Verificar Trabajo Ejecutado

## Propósito

El verificador no confía en que el código existe porque el desarrollador lo dice.
Verifica activamente, nivel por nivel, que cada entregable del plan está presente,
tiene implementación real (no stub), está conectado al sistema y los datos fluyen
a través de él de extremo a extremo.

## Cuándo activar

- Después de ejecutar una fase completa
- Antes de marcar una fase como "lista para producción"
- Cuando el usuario pide revisión o QA de trabajo entregado
- Como segunda opinión después de auto-reporte del desarrollador

## Cuándo NO cargar

- La tarea está en medio de la implementación — la verificación ocurre después de que el ejecutor declara que terminó.
- Se busca revisión de calidad de código (nombres, estructura, patrones); usar `checklist-calidad` o un skill de lenguaje específico.
- Se quiere auditar seguridad del código; usar `checklist-seguridad` o `threat-model-lite`.
- El objetivo es verificar el estado del sistema en producción en tiempo real; este skill verifica artefactos del plan, no métricas de runtime.

---

## Gate Function (verificacion micro)

Antes de CUALQUIER afirmacion de exito, aplicar este protocolo de 5 pasos:

1. IDENTIFICAR: que comando prueba esta afirmacion?
2. EJECUTAR: correr el comando COMPLETO (no parcial, no cached)
3. LEER: revisar output completo Y exit code
4. VERIFICAR: el output confirma la afirmacion?
5. AFIRMAR: solo entonces, con la evidencia

Red flags que activan el gate:
- "deberia funcionar", "se ve correcto", "probablemente pasa"
- Afirmaciones sin haber ejecutado verificacion
- "Los tests pasan" sin output de test runner

Este gate aplica en CADA afirmacion, no solo al final de una fase.
El skill `verificacion-evidencia` tiene el detalle completo de este protocolo.

---

## Taxonomía de claims (clasifica ANTES de verificar)

El nivel de evidencia requerido depende del tipo de claim que se quiere validar.
Antes de aplicar los 4 niveles, identifica qué clase de claim estás verificando.

Inspirado en `kiro-verify-completion` (cc-sdd) — ver `temp/cc-sdd-main/tools/cc-sdd/templates/agents/claude-code-skills/skills/kiro-verify-completion/SKILL.md`.

### Los 4 tipos de claim

| Claim type | Cuándo aplica | Evidencia mínima obligatoria |
|------------|---------------|-------------------------------|
| **TASK** | "Esta tarea está completa" — una sub-tarea atómica del PLAN.md | Niveles 1-3; tests locales de la tarea pasan; sin findings de revisor bloqueantes; evidencia alineada al boundary de la tarea |
| **FIX** | "Este bug está arreglado" — corrección de un defecto reportado | Síntoma original reproducido antes del fix + ya no se reproduce después; sin regresiones en el scope relevante |
| **TEST_OR_BUILD** | "Los tests pasan" / "el build pasa" — claim mecánico | Output literal del comando + exit code 0; conteo de pass/fail/skipped explícito; NO inferir desde checks no relacionados |
| **FEATURE_GO** | "Esta feature/fase está lista para producción" — claim de cierre mayor | Suite de tests completa verde + smoke test runtime (la app realmente arranca a estado usable) + cobertura de requisitos evaluada + alineación end-to-end con design + integración cross-task verificada |

### Reglas duras

1. **Identifica el claim type ANTES** de seleccionar evidencia. No reverse-engineer "qué tipo es" desde la evidencia que ya tienes.
2. **Rechaza claims más amplios que la evidencia**. Si solo verificaste una tarea (TASK), no puedes emitir FEATURE_GO. Reporta el alcance real.
3. **Para TEST_OR_BUILD**: la evidencia es el output del comando, no la inferencia. Si los tests pasan pero hay 47 skipped por preconditions falsas, NO es un Pass limpio — reporta los skipped como riesgo (ver regla `monitor-ci.md` § "verde con N skipped").
4. **Para FEATURE_GO**: un test suite verde NO basta. Requiere también smoke runtime, cobertura de requisitos y alineación end-to-end.
5. **Si la validación canónica no puede completarse** (sin BD disponible, sin red, sin runtime), retorna `MANUAL_VERIFY_REQUIRED` en lugar de inventar evidencia.

### Mapeo a salidas del veredicto

El claim type se incluye en el veredicto estructurado JSON:

```json
{
  "claim_type": "TASK | FIX | TEST_OR_BUILD | FEATURE_GO",
  "claim_text": "Tarea 3.2 — Crear endpoint POST /facturas",
  "verdict": "VERIFIED | NOT_VERIFIED | MANUAL_VERIFY_REQUIRED",
  "scope_evidence_match": "exact | broader_claim_than_evidence | narrower_claim_than_evidence",
  ...
}
```

Si `scope_evidence_match` es `broader_claim_than_evidence`, el verdict se
degrada automáticamente a `NOT_VERIFIED` con instrucción de re-emitir el
claim con scope acotado.

---

## Los 4 niveles de verificación

### Nivel 1 — EXISTE

**Pregunta**: ¿El artefacto prometido existe en el sistema de archivos / codebase?

Verificaciones:
- El archivo existe en la ruta esperada
- La clase / función / componente declarado está presente
- La migración de BD está en la carpeta correcta
- El endpoint está registrado en el router

Señal de falla: el archivo no existe, o existe pero está vacío, o existe pero
tiene solo el esqueleto generado automáticamente sin contenido real.

```bash
# Verificación de existencia
ls -la [ruta esperada]
grep -r "class [NombreEsperado]" .
grep -r "router\.[get|post|put|delete].*[ruta esperada]" .
```

### Nivel 2 — SUSTANTIVO

**Pregunta**: ¿La implementación tiene contenido real, no es un stub?

Un stub es cualquiera de:
- Función que solo tiene `pass` / `return null` / `throw new Error("not implemented")`
- Componente que solo renderiza un placeholder pendiente
- Service que solo tiene la firma pero no lógica
- Test que solo tiene `assert True` / `expect(true).toBe(true)`

Verificaciones por tipo:

| Tipo de artefacto | Señal de stub | Verificación real |
|------------------|--------------|------------------|
| Función Python | Solo `pass` o `return None` | Tiene lógica de negocio |
| Endpoint FastAPI | Solo `return {}` | Llama a un service |
| Componente Angular | Solo `<div>pendiente</div>` | Tiene template con datos reales |
| Test | Solo `assert True` | Tiene assert sobre comportamiento real |
| Migración SQL | Archivo vacío | Tiene operaciones DDL |

### Nivel 3 — CONECTADO

**Pregunta**: ¿El artefacto está integrado con los demás componentes del sistema?

Verificaciones:
- El endpoint está importado y registrado en el router principal
- El service es llamado desde el endpoint (no implementado en paralelo sin uso)
- El componente Angular está declarado en el módulo o importado en el componente padre
- La migración está en la secuencia correcta (no rompe la cadena de alembic/flyway)
- El modelo ORM está importado donde se usa

```bash
# Verificar que endpoint está registrado
grep -r "include_router\|app.include" . --include="*.py"

# Verificar que service es importado
grep -r "from.*service import\|import.*Service" . --include="*.py" --include="*.ts"

# Verificar cadena de migraciones (Alembic)
alembic history | head -20
```

Señal de "orphan": el artefacto existe y tiene contenido, pero nadie lo llama.
Un componente huérfano es código muerto desde el día uno.

### Nivel 4 — DATOS_FLUYEN

**Pregunta**: Si envío datos reales al sistema, llegan al destino correcto?

Este es el nivel más importante y el más difícil de falsear. Requiere ejecutar
el sistema o correr tests de integración.

Estrategias de verificación:

**Para APIs REST**:
```bash
# Llamada real al endpoint y verificar respuesta
curl -X POST http://localhost:8000/api/v1/[recurso] \
  -H "Content-Type: application/json" \
  -d '{"campo": "valor"}' | jq .

# Verificar que el dato llegó a la BD
psql -c "SELECT * FROM [tabla] ORDER BY created_at DESC LIMIT 1;"
```

**Para componentes Angular**:
- El componente renderiza datos de la API (no mocks hardcodeados)
- Los formularios envían datos al service correcto
- Los errores de la API se muestran al usuario

**Para jobs y cron**:
- El job se ejecuta y produce el output esperado
- Los logs muestran la ejecución correcta

---

## Detección de antipatrones comunes

### Hollow Component
Un componente Angular que:
- Tiene template pero no usa señales/variables del componente
- Tiene métodos declarados pero no llamados desde el template
- Recibe `@Input()` pero nunca lo renderiza

### Endpoint Stub
Un endpoint FastAPI que:
- Devuelve datos hardcodeados sin consultar la BD
- No valida el body (acepta cualquier cosa)
- No usa el `db: AsyncSession` declarado en la firma

### Test sin Valor
Un test que:
- No tiene ningún `assert` o `expect`
- Hace assert sobre un valor hardcodeado que siempre es true
- Prueba el mock en lugar del código real

### Migración Fantasma
Una migración que:
- Está en la carpeta pero no en la cadena de Alembic
- Tiene `upgrade()` vacío
- No corresponde con los modelos ORM actuales

---

## Veredicto estructurado (JSON)

Toda verificación DEBE producir un veredicto en formato JSON estructurado además
del reporte VERIFICACION.md legible. El veredicto es consumible por el orquestador
y por hooks de automatización.

### Schema del veredicto

```json
{
  "verdict": "Pass | Fail",
  "risk": "Low | Medium | High",
  "score": 0.85,
  "evidence": [
    {
      "level": "EXISTE | SUSTANTIVO | CONECTADO | DATOS_FLUYEN",
      "artifact": "src/api/endpoints.py",
      "status": "Pass | Fail",
      "detail": "Endpoint registrado en router principal línea 42"
    }
  ],
  "failures": [
    {
      "artifact": "src/services/pago_service.py",
      "level": "SUSTANTIVO",
      "reason": "Función procesar_pago() solo contiene pass"
    }
  ],
  "nextStep": {
    "action": "Continue | Fix | Escalate",
    "instructions": [
      "Implementar lógica real en procesar_pago()",
      "Agregar test de integración para flujo de pago"
    ]
  }
}
```

### Reglas del veredicto

- `verdict`: **Pass** solo si TODOS los artefactos pasan los 4 niveles. Un solo Fail → Fail.
- `score`: proporción de (artefactos × niveles) que pasaron. Rango 0.0 a 1.0.
- `evidence`: al menos una entrada por artefacto verificado. Sin evidencia = sin veredicto.
- `failures`: vacío si verdict es Pass. Obligatorio si es Fail.
- `nextStep.action`: **Continue** (pasar a siguiente fase), **Fix** (reparar y re-verificar),
  **Escalate** (requiere decisión humana — checkpoint `decision`).

### Loop de reparación

Cuando el veredicto es **Fail** con `nextStep.action: "Fix"`:

1. El verificador emite el veredicto con instrucciones concretas en `nextStep.instructions`.
2. El ejecutor aplica las correcciones indicadas (NO inventa correcciones adicionales).
3. El verificador re-ejecuta la verificación COMPLETA (no solo los items fallidos).
4. Si el veredicto sigue siendo Fail tras 2 intentos → escalar a `nextStep.action: "Escalate"`.

El ejecutor NUNCA se auto-verifica — el verificador es siempre un agente distinto
o una segunda invocación independiente.

---

## Clasificación de riesgo del cambio

El campo `risk` del veredicto se determina automáticamente según las características
del cambio verificado:

| Señal | Riesgo | Justificación |
|-------|--------|---------------|
| Eliminaciones de archivos o renombramientos | **High** | Puede romper imports y referencias |
| Migraciones de BD (DDL) | **High** | Irreversible en producción |
| Cambios en ≥12 archivos | **High** | Blast radius amplio |
| Cambios en ≥6 archivos o toca backend | **Medium** | Impacto moderado |
| Cambios en archivos de configuración (.env, CI) | **Medium** | Afecta infraestructura |
| Cambios en <6 archivos solo frontend | **Low** | Impacto contenido |
| Cambios solo en tests o documentación | **Low** | Sin impacto en producción |

### Verificaciones dinámicas por riesgo

El verificador ajusta su profundidad según el riesgo detectado:

- **Low**: Niveles 1-3 obligatorios. Nivel 4 recomendado.
- **Medium**: Los 4 niveles obligatorios. Ejecutar linter y type-checker si existen.
- **High**: Los 4 niveles obligatorios. Ejecutar tests completos. Verificar que
  `package.json` scripts (test, typecheck, lint) pasan. Revisar diff contra main.

Detección automática de scripts disponibles:
```bash
# Detectar qué verificaciones están disponibles
node -e "const p=require('./package.json');console.log(JSON.stringify(p.scripts||{}))" 2>/dev/null
# Ejecutar condicionalmente
npm run typecheck 2>/dev/null && echo "TYPECHECK_OK" || echo "TYPECHECK_FAIL"
npm test 2>/dev/null && echo "TESTS_OK" || echo "TESTS_FAIL"
```

---

## Plantilla de salida: `VERIFICACION.md`

Para la plantilla completa con todos los campos incluyendo el bloque de veredicto
estructurado JSON, ver [recursos/plantilla-verificacion.md](recursos/plantilla-verificacion.md).

---

## Gotchas / Errores comunes no obvios

- **Verificación parcial elevada a veredicto Pass**: el agente verifica solo los Niveles 1-2 para un cambio de riesgo High y reporta Pass porque esos dos niveles pasaron. Causa: no se aplicaron las verificaciones dinámicas por riesgo. Solución: para cambios High, los 4 niveles son obligatorios y además se ejecutan los scripts `test`, `typecheck` y `lint` de `package.json`.
- **Score del veredicto calculado solo sobre artefactos verificados, no sobre todos los prometidos**: si el plan prometía 8 entregables pero solo se verificaron 5, el score 1.0 sobre los 5 no es evidencia de que los 8 están correctos. Causa: el agente omite entregables del plan en la lista de artefactos. Solución: antes de verificar, listar todos los artefactos del PLAN.md y verificar cada uno explícitamente — un artefacto no verificado es un Fail implícito.
- **Loop de reparación sin re-verificación completa**: tras el fix, el agente re-verifica solo el item que falló en lugar del veredicto completo. Causa: optimización incorrecta para ahorrar tiempo. Solución: el paso 3 del loop de reparación dice explícitamente "re-ejecutar la verificación COMPLETA" — un fix puede resolver un fallo pero introducir otro.
- **Hollow Component no detectado en Nivel 2**: el componente Angular tiene template pero no usa ninguna señal del componente. El agente verifica que el archivo existe (Nivel 1) y que tiene contenido (Nivel 2), pero no detecta que el contenido es decorativo. Causa: la definición de "stub" en Nivel 2 no se aplicó al caso de templates sin binding. Solución: verificar explícitamente que el template usa al menos una variable/señal del componente.
- **Verificación con tests + linter pasa pero al levantar BD fresca todo se rompe**: tests Python con mocks y `ruff check` retornan verde, pero `docker compose down -v && up` falla porque hay drift entre `database/schemas/`, seeds, funciones SQL y vistas. Caso real (SIGM 2026-05-04): primera pasada de `/swl:verificar` reportó "APROBADO 21/22" sin detectar que ~10 seeds tenían columnas obsoletas, UUIDs inválidos y un script `02-crear-buckets-minio.sh` que abortaba initdb del contenedor postgres. Causa: la verificación corre solo contra el código (que mockea BD); nunca aplica el SQL real. Solución: cuando el alcance toca cualquier archivo en `database/schemas/`, `database/seeds/`, `database/functions/` o `database/views/`, ejecutar como Nivel 4 (DATOS_FLUYEN) obligatorio: `docker compose down -v && docker compose up -d db && wait_for_health && docker logs <db_container> | grep -E "ERROR|skipped"`. Cualquier ERROR en logs de init invalida el veredicto Pass.
- **Health-check post-hoc que recalcula contexto del install desde cwd actual produce falso positivo**: un verificador (doctor, validador, monitor) que recalcula filtros — aplicados al momento del install — desde el `process.cwd()` actual genera discrepancia falsa cuando se ejecuta desde un dir distinto. Caso real (swl-ses doctor v1.4.3, 2026-05-15): reportaba "reglas: 65 (perfil esperaba 25)" porque recalculaba `filtrarReglasPorStack(detectarStack(cwd))` con `cwd` vacío de indicadores, mientras las 40 reglas-lenguajes se habían instalado correctamente con stack detectado en el dir del proyecto. Causa: el filtro depende del contexto del momento del install, no del momento del check. Solución obligatoria: **persistir el contexto del install en el state file** (en este caso `allLangs` + `stackInstalado` en `.swl-install-state.json`). Si el state es legacy (sin estos campos), **inferir el contexto desde los archivos realmente instalados** (ej: subdirs presentes bajo `reglas/lenguajes/<lang>/`), NO recalcular desde cwd. Aplica como regla general a cualquier check post-hoc cuya validez depende del contexto del install.

- **Suite 100% verde con bug latente cross-cutting que solo aparece en smoke E2E real**: las unit tests del transformador pasaban, los tests del instalador pasaban, los tests del manifiesto pasaban — pero el smoke `install --target codex --local --force` reveló que `instalarArchivo()` hacía `fs.copyFileSync(archivo.origen, destino)` literal sin invocar `transformarAgente()`. Los `.toml` de Codex y los `.md` normalizados de Cursor NUNCA se generaban en disco aunque las unit tests del transformador retornaran contenido correcto. Caso real (Sub-fase 11.5 v1.5.1, 2026-05-15): la integración de las dos capas (transformador + instalador) jamás se testeaba E2E porque cada una se probaba en aislamiento con mocks. **Regla obligatoria para features cross-cutting** (multi-capa: transformador + instalador + filesystem; o lib + bin + cliente; o backend + frontend + cache): el Nivel 4 DATOS_FLUYEN exige al menos un smoke E2E real que ejercite las tres capas con archivos reales en disco temporal. NO sustituible por unit tests aunque la suite sea 100% verde. Comando mínimo: `mkdir tmp && cd tmp && bin/CLI <comando-happy-path> && ls -R` + inspección del primer archivo generado.

- **Auto-reparación ejecuta acción sin verificar que el chequeo subsecuente ya no detecta el problema**: el doctor reporta "faltan reglas: 0/25" en Codex, el usuario elige "reparar automáticamente", el doctor invoca `instalador.install({force:true})`, reinstala 230 archivos, vuelve a chequear y reporta lo mismo. Loop infinito. Caso real (Sub-fase 12 v1.5.1, 2026-05-15): los 4 falsos positivos del doctor sobre Codex/Cursor persistían tras cada "reparación" porque la causa raíz era un filtro hardcoded (`tiposPrincipales = ['agentes', 'habilidades', 'comandos', 'reglas']` sin respetar `runtime.tiposSoportados` ni `dir<Tipo>`). Cada reinstalación dejaba el filtro intacto, el chequeo seguía detectando el "problema". **Regla**: toda función de auto-reparación debe ejecutar el chequeo subsecuente ANTES de reportar "Reparado" — si el chequeo sigue detectando el problema, NO marcar como reparado y reportar "no se pudo reparar, requiere diagnóstico manual". Implementación: wrap la acción en `try { accion(); const res = chequeo(); if (!res.ok) throw new Error('reparación sin efecto'); }`.

## Regla de oro del verificador

**"Si no puedes mostrar evidencia, no puedes decir que pasa."**

Cada nivel PASS debe tener evidencia adjunta en el reporte. Un "creo que funciona"
o "debería estar conectado" no es evidencia. La evidencia es:
- Output de un comando
- Línea de código específica
- Output de un test
- Screenshot o log de ejecución
