¿Construimos el producto correctamente, o construimos el producto correcto?
/docs/testing ya documenta 15 niveles de prueba con sus métricas reales. Esta página no repite ese inventario: lo reclasifica bajo un marco distinto —verificación y validación (IEEE 1012)— que responde una pregunta que el inventario técnico no hace explícita: de esos 15 niveles, ¿cuáles comprueban que el código cumple su propia especificación, y cuáles comprueban que el sistema le sirve a alguien de verdad?
El marco: dos preguntas, no una
«Testing» suele tratarse como una sola actividad. IEEE 1012 la separa en dos porque tienen oráculos distintos —la fuente de verdad contra la que se compara un resultado— y confundirlos hace que un pipeline en verde se sienta como garantía de algo que nunca prometió.
Verificación
¿Estamos construyendo el producto correctamente?
Conformidad interna: el código hace lo que su propia especificación dice que debe hacer. No necesita a nadie fuera del equipo — un esquema, un contrato o una línea de código ya definen qué es «correcto».
Validación
¿Estamos construyendo el producto correcto?
Conformidad externa: el sistema sirve para lo que una persona real necesita hacer con él. La vara no es una especificación interna, es alguien —o algo que simula a alguien— tratando de cumplir un objetivo real.
Nivel de integridad: no todo merece el mismo rigor
Verificación y validación responden qué se comprueba. IEEE 1012 responde una segunda pregunta, independiente de esa: cuánto rigor exige cada parte del sistema. La clasifica en 4 niveles según la consecuencia de que ese subsistema falle — no la probabilidad. A mayor nivel, más tareas de V&V son obligatorias. Aplicar el mismo esfuerzo de prueba a una página de contenido y al motor de cobros no sería más riguroso: sería mal presupuestado.
Catastrófica — dinero real perdido, fraude, credenciales de terceros expuestas
Grave — acceso no autorizado al panel o a datos personales de un cliente
Degradación operativa — se pierde visibilidad, no hay compromiso directo de datos
Negligible — inconveniencia visual, nada operativo se rompe
Pagos y cobros (Wompi)
nivel 4 · CríticoUn fallo aquí es dinero real: doble cobro, estado de pago inconsistente entre pasarela y base propia.
src/lib/payments.ts, payments-state.ts, cobros*.ts
↳ Pendiente: Falta cubrir con concurrencia real todas las transiciones de la máquina de estados, no solo el camino feliz.
Bóveda de secretos (project_services.secrets)
nivel 4 · CríticoUn fallo expone credenciales de terceros cifradas con AES-256-GCM a quien no debería verlas.
src/lib/crypto.ts, src/lib/vault.ts, project_services.secrets
↳ Pendiente: Un nivel 4 pediría además revisión independiente del propio cifrado: hoy el diseño criptográfico lo audita quien lo escribió.
Autenticación (admin OAuth+allowlist, portal scrypt)
nivel 3 · AltoUn fallo da acceso no autorizado al panel de control o a los datos de un cliente en el portal.
auth.config.ts, src/lib/auth.ts (admin) — src/lib/portal/session.ts, login.ts (portal)
↳ Pendiente: Los casos negativos de revocación se prueban a mano; un nivel 3 pediría cubrirlos también de forma automatizada.
Middleware de seguridad (clasificador, rate limit, blocklist)
nivel 3 · AltoUn fallo permite el bypass de un atacante. El diseño fail-open acota el daño a «no protege», nunca a «tumba el sitio».
src/lib/security/*
Micro-SIEM, crons, notificaciones
nivel 2 · ModeradoUn fallo pierde visibilidad operativa, no compromete datos directamente — proporcional al no-op silencioso con que ya están diseñados.
src/lib/notify.ts, src/pages/api/cron/*
Contenido público (/notes, /status, /tools)
nivel 1 · BajoUn fallo es inconveniencia visual. Nada operativo ni financiero depende de que estas páginas rendericen bien.
src/pages/*.astro (rutas públicas)
El requisito de nivel 4 que este proyecto no puede cumplir. Para los niveles de integridad más altos, IEEE 1012 no solo pide más tareas: pide que las ejecute alguien independiente de quien escribió el código —presupuesto, personal y línea de reporte separados (IV&V)—. La razón es que el autor de un módulo comparte los puntos ciegos de su propio diseño: no se le ocurre probar el caso que no se le ocurrió programar. Un proyecto de una sola persona no puede satisfacer eso, y ninguna cantidad de tests lo compensa. Lo más cerca que llega este repositorio son sustitutos parciales que no dependen del criterio del autor: herramientas externas con su propio catálogo de reglas (CodeQL, axe-core, OWASP ZAP), el mutation testing —que ataca las pruebas en vez de confiar en ellas— y la validación con usuarios, el único punto donde el juicio viene de fuera de verdad. Es una limitación estructural, no una tarea pendiente.
Verificación — 12 niveles
La mayoría de los niveles de este repositorio son verificación, y tiene sentido que lo sean: son baratos, automatizables y no dependen de conseguir a una persona real. El oráculo en todos estos casos lo escribió alguien del equipo antes que el código.
Unitario / lógica pura
· VitestCompara la salida de una función contra lo que su propia firma promete. La vara la puso quien escribió el código, no un usuario.
Integración con BD real
· Vitest + libSQL en archivo temporalComprueba que un UNIQUE o una transacción se comportan como dice el esquema. Sigue siendo una afirmación interna sobre el sistema, no sobre su uso.
Contratos de API
· Vitest + ZodUn esquema Zod es la especificación. Verificar contra tu propio esquema es el caso más puro de «¿lo construimos como dijimos que lo íbamos a construir?».
Cobertura de código
· @vitest/coverage-v8Mide qué parte del código se ejecutó contra la propia suite. No dice nada sobre si ese código sirve para algo real.
Mutation testing
· Stryker + runner de VitestComprueba que los propios tests defienden lo que dicen defender. Es verificación de la verificación, no toca al usuario en ningún momento.
SAST de dependencias
· npm audit → panel LAB propioCompara versiones de dependencias contra una lista de advisories publicados. Conformidad contra una base de datos externa, no contra una necesidad de un usuario.
SAST de código
· CodeQL (javascript-typescript)Análisis estático de patrones de código contra reglas conocidas de vulnerabilidad. No ejecuta nada ni involucra a nadie usando el sistema.
Verificación en producción
· curl + /api/health + vercel rollbackUn health check confirma que el proceso desplegado es el que se esperaba desplegar. Es fidelidad al propio despliegue, no a una expectativa de usuario.
Chaos engineering
· Flags en BD + middleware propioConfirma que el sistema se degrada como el diseño de resiliencia dice que debe degradarse. La especificación es interna: «esta ruta nunca debe romperse».
Monitoreo sintético
· Monitores propios + cron externoSondea si el sistema sigue respondiendo lo que su contrato de servicio promete (disponibilidad). No mide si a alguien le sirve lo que responde.
Pruebas de carga
· k6 (pendiente)Comprueba que la latencia se mantiene dentro de un presupuesto definido por ingeniería, no por un usuario real observado.
DAST (análisis dinámico)
· OWASP ZAP baselineCompara el comportamiento del sitio en ejecución contra un catálogo externo de patrones de vulnerabilidad conocidos (OWASP), igual que SAST pero en caliente. El oráculo sigue siendo un estándar, no una persona usando el sistema.
Validación — 3 niveles
Aquí el oráculo deja de ser un archivo del repositorio. En e2e es una persona simulada completando un objetivo; en accesibilidad, alguien con lector de pantalla; en usabilidad, una persona real y nadie más. Por eso son los niveles más caros de esta lista, y también los que más se parecen a lo que de verdad importa: que el sistema le sirva a alguien.
End-to-end
· Playwright (Chromium)No compara contra una especificación interna: simula a una persona con un navegador tratando de completar un objetivo real (pagar, ingresar, contratar). Si el flujo cambió de forma que ya no sirve, un e2e bien escrito lo nota aunque el código «cumpla su contrato».
Accesibilidad
· axe-core + PlaywrightLa vara no es el propio código: es si una persona con lector de pantalla o sin ratón puede usar la página. axe-core es un proxy automatizado de esa pregunta —cubre ~30-40%— pero la pregunta que responde es externa al sistema, no interna.
Usabilidad con usuarios
· Metodología de 6 pasosEl único nivel donde no hay ninguna especificación que verificar: el resultado es una observación de alguien que no construyó el sistema intentando usarlo. Es la validación en su forma más literal.
El desbalance es a propósito, no un hueco. 12 niveles de verificación contra 3 de validación no significa que la validación importe menos — significa que cuesta más y no se puede automatizar del todo. De los 3, solo usabilidad exige a una persona real cada vez; e2e y accesibilidad usan proxies automatizados (un navegador sin ojos, un escáner de reglas WCAG) que se acercan a la pregunta de validación sin necesitar a alguien en cada corrida. Es el motivo por el que la evidencia de usabilidad con participantes reales sigue siendo el hueco más honesto de todo el proyecto.
La frontera no siempre es limpia
Tres casos de este repositorio muestran por qué la clasificación de arriba es una decisión, no un hecho objetivo — y por qué conviene decirlo en vez de esconderlo.
E2E: automatizado pero externo
Se ejecuta en CI como un test más —sin persona presente— pero lo que compara es un flujo completo contra una expectativa de uso, no una función contra su firma. Se clasificó como validación por el oráculo que usa, no por cómo se ejecuta.
Accesibilidad: validación con proxy
axe-core corre en CI y verifica contra reglas WCAG, lo cual suena a verificación. Pero esas reglas existen para aproximar una pregunta de validación (¿puede usarlo alguien con una discapacidad?) que ninguna herramienta responde del todo — de ahí que cubra solo ~30-40% de los problemas reales.
Requerimientos no funcionales: verificación disfrazada
ISO/IEC 25010 (ver requerimientos no funcionales) parece hablar de calidad para el usuario, pero cada atributo (tiempo de respuesta, tasa de errores) se verifica contra un umbral fijado por ingeniería, no contra la observación directa de alguien usándolo.
De la necesidad al test: dónde vive cada mitad
Esta página no es el único lugar donde vive V&V — es el mapa que conecta documentos que ya existían por separado. La validación empieza antes que cualquier test: en el caso de uso o la historia que dijo qué necesidad real se estaba resolviendo.
La validación empieza aquí: cada caso de uso es una necesidad real de un actor, escrita antes que el código.
Su Definition of Done es el criterio de validación en formato XP: cuándo una historia sirve de verdad, no solo cuándo compila.
ISO/IEC 25010 es, en el fondo, un catálogo de propiedades verificables (rendimiento, seguridad, mantenibilidad) — el lado de verificación de este mismo mapa.
El detalle técnico completo de cada nivel: herramienta, volumen, archivos, punto ciego. Esta página los reclasifica; esa los explica uno por uno.
La metodología de validación con usuarios en 6 pasos, aplicada a un flujo real del sitio.
Los procesos del ciclo de vida
IEEE 1012 no ata las tareas de V&V a «niveles de prueba» — las ata a fases del ciclo de vida del software, desde la gestión del propio plan hasta el mantenimiento. Este repositorio cubre casi todas sin haberlas llamado así nunca; esta tabla es esa traducción, en el orden en que ocurren.
Cómo correrlas tú mismo
Cuatro comandos, cada uno respondiendo una pregunta distinta. Ninguno necesita nada externo: la suite de Vitest usa libSQL en archivo temporal y la de Playwright siembra su propia base desechable al levantar el servidor.
npm testverificacionCorre la suite de Vitest una sola vez: pruebas unitarias (funciones puras en src/lib/) y de integración (las que sí tocan una libSQL temporal). Es el comando de verificación más barato y el que más rápido detecta una regresión.
npm run test:coverageverificacionLa misma suite de Vitest, pero midiendo qué porcentaje de líneas y ramas del código ejecuta al menos un test. No agrega pruebas nuevas — sirve para ver qué partes del repositorio nadie está verificando todavía.
npm run test:e2evalidacionPlaywright abre un navegador real y simula a una persona completando un flujo completo (login, cobro, portal) contra una base de datos desechable. Es validación porque el oráculo es "¿esto le sirve a alguien navegando de verdad?", no la firma de una función.
npx astro checkverificacionVerificación de tipos con TypeScript sobre todo el proyecto (páginas .astro incluidas). No es una suite de tests en sentido estricto, pero se corre junto porque detecta errores antes de que lleguen a build: propiedades que no existen, imports rotos, valores posiblemente undefined.
Glosario
- IEEE 1012
- El estándar que formaliza la distinción verificación/validación para software (Verification and Validation Plans). No define herramientas, solo el marco de preguntas.
- V-model
- Representación clásica del ciclo de vida donde cada etapa de construcción tiene su etapa de verificación espejo. Aquí no se sigue el modelo en cascada, pero la pregunta de cada espejo sigue aplicando.
- Oráculo
- La fuente de verdad contra la que se compara un resultado. En verificación el oráculo es interno (un esquema, un contrato); en validación el oráculo es una necesidad externa, a menudo humana.
- UAT
- User Acceptance Testing: validación formal hecha por quien va a usar o pagar por el sistema, no por quien lo construyó. Este proyecto no tiene un UAT formal separado — el usability testing y los casos de uso cumplen ese rol.
- Nivel de integridad
- Clasificación de IEEE 1012 (1 a 4) según la consecuencia de que un subsistema falle, no según la probabilidad de que falle. A mayor nivel, más tareas de V&V son obligatorias.
- IV&V
- V&V independiente: la ejecuta alguien con presupuesto, personal y línea de reporte separados de quien desarrolló. IEEE 1012 la exige en los niveles de integridad altos, porque el autor de un módulo comparte los puntos ciegos de su propio diseño. Un proyecto de una persona no puede cumplirla.