Mike (@mikerb95)CodeByMike

¿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?

12
Verificación
¿lo construimos bien?
3
Validación
¿construimos lo correcto?
15
Niveles totales
detalle en /docs/testing
5
Documentos ligados
de casos de uso a testing

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.

Nivel 4 · Crítico

Catastrófica — dinero real perdido, fraude, credenciales de terceros expuestas

Nivel 3 · Alto

Grave — acceso no autorizado al panel o a datos personales de un cliente

Nivel 2 · Moderado

Degradación operativa — se pierde visibilidad, no hay compromiso directo de datos

Nivel 1 · Bajo

Negligible — inconveniencia visual, nada operativo se rompe

Pagos y cobros (Wompi)

nivel 4 · Crítico

Un 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

Unitario / lógica puraIntegración con BD realContratos de APIMutation testingEnd-to-end

↳ 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ítico

Un 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

Unitario / lógica puraSAST de códigoSAST de dependencias

↳ 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 · Alto

Un 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)

Integración con BD realEnd-to-endDAST (análisis dinámico)

↳ 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 · Alto

Un 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/*

Unitario / lógica puraIntegración con BD realChaos engineeringDAST (análisis dinámico)

Micro-SIEM, crons, notificaciones

nivel 2 · Moderado

Un 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/*

Unitario / lógica puraMonitoreo sintético

Contenido público (/notes, /status, /tools)

nivel 1 · Bajo

Un fallo es inconveniencia visual. Nada operativo ni financiero depende de que estas páginas rendericen bien.

src/pages/*.astro (rutas públicas)

End-to-endAccesibilidad

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

· Vitest

Compara 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 temporal

Comprueba 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 + Zod

Un 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-v8

Mide 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 Vitest

Comprueba 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 propio

Compara 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 rollback

Un 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 propio

Confirma 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 externo

Sondea 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 baseline

Compara 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.

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.

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.

GestiónPlan de V&V y asignación de nivel de integridad por riesgoEsta página + docs/plan-*.md
Adquisición / suministroAuditoría de dependencias y librerías de tercerosnpm audit, CodeQL
Desarrollo — ConceptoEvaluación de la necesidad real antes de escribir código/docs/casos-de-uso
Desarrollo — RequisitosTrazabilidad de cada requisito a una prueba concreta/docs/historias-de-usuario, /docs/requerimientos-no-funcionales
Desarrollo — DiseñoEvaluación de interfaces contra su especificaciónContratos Zod (tests/contracts.test.ts)
Desarrollo — ImplementaciónRevisión del código fuente y de sus propias pruebasUnitarias + mutation testing
Desarrollo — PruebaGeneración y ejecución de casos de pruebaUnitarias, integración, e2e
Desarrollo — InstalaciónAuditoría de configuración tras el desplieguejob verify-production, health checks
OperaciónMonitoreo continuo y detección de anomalíasMonitoreo sintético + micro-SIEM
MantenimientoAnálisis de impacto de cada cambio antes de fusionarloSuite de regresión en cada push

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 testverificacion

Corre 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:coverageverificacion

La 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:e2evalidacion

Playwright 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 checkverificacion

Verificació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.