Mike (@mikerb95)CodeByMike

114 historias en formato XP ("Como <actor>, quiero <acción> para <beneficio>"), consolidadas desde el kanban del proyecto (108 aceptadas de 114). Agrupadas por el rol del actor; cada una conserva su Definition of Done y la iteración de origen -ver en el tablero →.

Como visitante (21)

PF-F-01historia
Aceptada

Como visitante, quiero ver el portfolio público con proyectos reales para evaluar el trabajo de Mike

#astro#público#fase-1Fase 1 · Fundación · Bootstrap del portfolio: Astro, auth y CRM base
  • BaseLayout, Navbar, Footer y la página principal con hero, proyectos y proceso quedan operativos.
  • ProjectCard consume datos reales de GitHub vía API de repos.
  • Tailwind CSS v4 configurado con paleta y tipografía del sitio.
PF-VS-01historia
Aceptada

Como visitante, quiero ver el estado en vivo de los servicios (uptime, incidentes, latencia)

#status#público#fase-4Fase 4 · Vitrina y SEO · Vitrina pública, status page, EKG y capa técnica de SEO
  • /status muestra uptime global de 30 días e incidentes activos.
  • Animación EKG con latencia p95 en tiempo real por monitor (13 commits de status).
  • API de latencia expone último estado y hora de chequeo por monitor.
PF-VS-02historia
Aceptada

Como visitante, quiero que el sitio sea indexable y compartible (SEO técnico completo)

#seo#fase-4Fase 4 · Vitrina y SEO · Vitrina pública, status page, EKG y capa técnica de SEO
  • JSON-LD y breadcrumbs estructurados en páginas de proyecto.
  • Feed RSS y notificación IndexNow a buscadores en cada publicación (8 commits de IndexNow).
  • Web app manifest y apple-touch-icon para instalación como PWA.
PF-VS-03historia
Aceptada

Como visitante, quiero una vitrina pública de herramientas y notas técnicas del stack

#vitrina#notas#fase-4Fase 4 · Vitrina y SEO · Vitrina pública, status page, EKG y capa técnica de SEO
  • Secciones /tools y /notes publicadas con 5 artículos técnicos iniciales.
  • OG images generadas dinámicamente para cada nota/proyecto.
PF-FP-01historia
En aceptación

Como visitante, quiero escanear un QR y ver cómo un tablero reconoce mi dispositivo en vivo sin cookies

#fingerprint#público#fase-7Fase 7 · Lab educativo · Laboratorio de fingerprinting en vivo (Sala de espejos)
  • Landing con consentimiento crea sala + QR; el tablero (/board) refleja los dispositivos por polling corto (Vercel no soporta WebSocket).
  • Al reentrar en incógnito o borrar cookies, el contador de "revisitas" sube: mismo dispositivo re-identificado (validado por smoke test de API).
  • ·Prueba end-to-end en navegador real del ciclo crear → escanear → revisita (canvas/WebGL/audio solo producen valores en un browser).
PF-FP-02historia
En aceptación

Como visitante, quiero entender qué me delata: recolector propio contrastado con una librería y una capa de comportamiento

#fingerprint#híbrido#fase-7Fase 7 · Lab educativo · Laboratorio de fingerprinting en vivo (Sala de espejos)
  • Recolector propio: canvas, WebGL, AudioContext, fuentes, pantalla, zona horaria, CPU/memoria, idiomas, touch y UA.
  • Segunda opinión con FingerprintJS (open source): su visitorId se muestra junto al hash propio en el tablero.
  • Entropía dinámica: cada señal bloqueada/vacía suma 0 bits; se declara como estimación educativa (EFF Panopticlick / AmIUnique), no medición poblacional.
  • Capa de comportamiento: cadencia de tecleo, velocidad de mouse y giroscopio (con permiso iOS 13+).
PF-PD-01historia
Aceptada

Como visitante, quiero explorar el portal de clientes de la demo con datos frescos, no con lo que dejó otro visitante

#demo#portal#fase-15Fase 15 · Demo del portal de clientes · Sembrado automático del portal demo y aviso de disponibilidad
  • seedPortalDemo siembra clientes, facturas y client_users ficticios en la base demo, reusando scripts/seed-demo.mjs.
  • Cron de Vercel resiembra el portal demo a las 4am todos los días (vercel.json).
  • Endpoint público de demo añadido a las rutas accesibles sin sesión; pagos bloqueados también en el portal demo (middleware).
PF-PD-02historia
Aceptada

Como visitante, quiero que se me avise claramente cuándo la demo del portal está disponible

#demo#portal#ux#fase-15Fase 15 · Demo del portal de clientes · Sembrado automático del portal demo y aviso de disponibilidad
  • Banner de demo en PortalLayout y mensajes de disponibilidad en login y /tools.
  • Flag demoAvailable/demoUnavailable propaga el estado real de la base demo a la UI.
  • Tests de creación y validación del token de sesión demo del portal.
PF-SI-01historia
Aceptada

Como visitante, quiero analizar cualquier dominio público (SEO, performance, accesibilidad, TLS) desde el sitio

#diagnóstico#público#fase-17Fase 17 · Analizador público de sitios · Herramienta pública de diagnóstico SEO, performance, accesibilidad y seguridad TLS
  • Endpoint público de análisis de dominio con rate limiting propio.
  • SSRF protegido: resolución de hostname y rechazo de IPs privadas/reservadas antes de solicitar el sitio.
  • Fetch del HTML memoizado y reutilizado entre las pruebas de SEO, performance y accesibilidad para no golpear el sitio objetivo varias veces.
  • Integración con Google PageSpeed Insights (Lighthouse) para las métricas de performance.
PF-SI-02historia
Aceptada

Como visitante, quiero entender qué hace la herramienta y confiar en que no expone mi sitio a riesgos

#diagnóstico#ux#fase-17Fase 17 · Analizador público de sitios · Herramienta pública de diagnóstico SEO, performance, accesibilidad y seguridad TLS
  • Sección "site analyzer" en /lab con enlace desde /tools y modal "How it works" explicando el proceso.
  • Nota técnica documentando cómo se analiza cualquier dominio sin poner en riesgo el propio servidor.
  • Normalización de emisor/sujeto del certificado TLS para mostrarlo de forma legible.
PF-PV-01historia
Aceptada

Como visitante, quiero una interfaz con más profundidad visual sin perder legibilidad

#ui#diseño#fase-20Fase 20 · Pulido visual y saneamiento de tech stack · Fondo con profundidad (blobs), separación de navbar y parser único de tech stack
  • Blobs de fondo degradados añadidos a BaseLayout con posicionamiento propio, sin interferir con el contenido.
  • Scrim detrás del navbar para mantener contraste sobre contenido con scroll.
PF-CV-01historia
Aceptada

Como visitante, quiero descargar el CV desde la página de contacto

#cv#público#fase-21Fase 21 · Descarga de CV con huella y auditoría · Descarga de CV con token de un solo uso, fingerprint y panel de estadísticas
  • Enlace de descarga de CV añadido a la página de contacto.
  • /api/cv/capture recibe las señales del dispositivo y emite un token de un solo uso; /api/cv/download lo valida antes de servir el archivo.
PF-LE-01historia
Aceptada

Como visitante, quiero seguir rutas de aprendizaje con labs cronometrados y marcar mi progreso

#educación#público#fase-22Fase 22 · Rutas de aprendizaje y bloqueo escalado de IPs · Open Security Labs con progreso persistente, IP blocking escalado y fixes de revisitas en fingerprinting
  • educationPaths define rutas, temas y labs con duración y nivel (Inicial/Intermedio/Avanzado).
  • Tabla educationLabProgress persiste qué labs completó cada visitante.
  • API de progreso y toggle en /admin para gestionar el estado de cada lab.
PF-VIS-01historia
Aceptada

Como visitante, quiero un fondo ambiental que se sienta vivo al hacer scroll sin distraer del contenido

#diseño#público#fase-23Fase 23 · Fondo ambiental y reorganización del footer · AmbientBlobs con paralaje por scroll y footer reagrupado por categoría
  • AmbientBlobs.astro reemplaza los gradientes estáticos de global.css; cada blob se mueve de forma independiente con paralaje por scroll.
  • El desplazamiento combina ondas senoidales de frecuencia irracional por blob para evitar un patrón mecánico perceptible.
  • prefers-reduced-motion desactiva transform y transición por completo.
  • position/isolation en el body corrigen el stacking context tras integrar el componente en BaseLayout.
PF-VIS-02historia
Aceptada

Como visitante, quiero encontrar rápido un enlace del footer sin escanear una sola lista larga

#diseño#accesibilidad#público#fase-23Fase 23 · Fondo ambiental y reorganización del footer · AmbientBlobs con paralaje por scroll y footer reagrupado por categoría
  • Footer.astro reagrupa los 12 enlaces en 5 categorías (Sitio, Producto, Ingeniería, Operación, Redes, Contacto directo).
  • Layout con flex-wrap reemplaza el grid de columnas fijas, evitando huecos vacíos en pantallas angostas.
PF-PL-01historia
Aceptada

Como visitante, quiero ver si el pipeline acaba de funcionar, no solo un diagrama de cómo funcionaría

#documentación#observabilidad#público#fase-26Fase 26 · Pipeline en vivo y captación de clientes no técnicos · Estado real del pipeline en /docs y landing comercial de diseño web
  • /docs/pipeline-en-vivo muestra el estado real de la última corrida, etapa por etapa, con recorrido paso a paso.
  • src/lib/lab/pipeline-live.ts aísla la normalización y el mapeo de estados como lógica pura; tests/pipeline-live.test.ts la cubre.
  • La etapa de push refleja la ocurrencia del evento, no el resultado de la corrida.
PF-PA-02historia
Aceptada

Como visitante, quiero que el sitio se sienta fluido al desplazarme sin que el scroll se vuelva pesado

#diseño#público#fase-27Fase 27 · Accesibilidad del portal y capa de movimiento · Salto al contenido, anuncios en vivo y foco explícito; scroll suave con Lenis y GSAP
  • Lenis para el scroll suave y GSAP para las animaciones de entrada, integrados en el layout público.
  • autoRaise retirado de la inicialización de Lenis por su coste en rendimiento del scroll.
PF-I18-03historia
Aceptada

Como visitante, quiero que ningún enlace en inglés me lleve a una página que no existe

#i18n#seo#público#fase-29Fase 29 · Internacionalización del sitio público · Versión en inglés bajo /en sin duplicar páginas ni abrir bypasses
  • TRANSLATED_ROUTES como única fuente de verdad de qué existe en inglés; localizedHref cae al español si no hay traducción.
  • El hreflang y el sitemap solo anuncian idiomas en los que la página existe de verdad.
  • El middleware redirige GET/HEAD de /en sin traducir a la versión en español con 302, no 308.
  • tests/i18n-routing.test.ts cruza la lista contra los archivos reales de src/pages/en/ en las dos direcciones.
PF-LT-02tarea
Aceptada

Como visitante, quiero recorrer la demo del panel con datos que no parezcan abandonados

#demo#operación#fase-30Fase 30 · Coste de las consultas de /status y demo encendida · Índices, lectura por lotes dentro del techo de Turso y siembra de la demo
  • Variables de la base demo en Production y Preview; base re-sembrada con 90 días de historial que terminan hoy.
  • resetSchema usa executeMultiple: contra Turso por HTTP cada execute viaja en su propia sesión y el pragma de foreign_keys se perdía.
  • Verificado en los dos backends (Turso y archivo local), dos corridas seguidas.
PF-CP-03historia
Aceptada

Como visitante, quiero entender qué se contrata antes de escribir

#capacitacion#publico#comercial#fase-36Fase 36 · Capacitación en IA como línea de negocio · Banco de recursos con acceso por código de grupo y landing de capacitación
  • Landing /capacitacion-ia con los programas publicados desde el panel: formato, nivel, duración, objetivos, temario desplegable y nota de precio. Ningún dato del catálogo se escribe en el .astro.
  • Si la lectura del catálogo falla, la landing sigue sirviendo hero, proceso y contacto en vez de caer.
  • El material del grupo va con noindex y Cache-Control private, no-store: la respuesta depende de una cookie y una copia compartida se le serviría a quien no tiene pase.
  • capacitacion y capacitacion-ia registradas en RESERVED_ROOT_SEGMENTS: son rutas de un segmento en la raíz y competían con el espacio de los PIN de presentación. Lo cazó el test del repo, no una revisión.
PF-CR-03historia
Aceptada

Como visitante, quiero que el sitio siga en pie cuando la base no responde

#resiliencia#publico#fase-37Fase 37 · Coste acotado, degradación elegante y respaldo verificable · Lo que se rompió cuando el sitio dejó de ser gratis de leer
  • safeQuery: una consulta que falla en una página pública devuelve su valor de reemplazo y el dato se pinta como ausente, nunca como error y mucho menos como 404.
  • Aplicado a las 23 consultas de las cinco páginas públicas con datos (portada, /status, /security, /certifications, /engineering); no queda ninguna consulta desnuda.
  • Cada fallo se registra con etiqueta en el log del servidor: degradar para el visitante no puede significar degradar en silencio para quien opera.
  • Excluido a propósito del panel, el portal y todo lo que cobra o autentica, donde un dato ausente en silencio es peor que un error visible.

Como administrador (30)

PF-F-02historia
Aceptada

Como administrador, quiero autenticarme y que solo yo pueda entrar a /admin

#auth#seguridad#fase-1Fase 1 · Fundación · Bootstrap del portfolio: Astro, auth y CRM base
  • Middleware de Astro protege todas las rutas /admin y /api/admin.
  • Auth.js con proveedor GitHub y allowlist de logins permitidos.
  • Base de datos Drizzle + libSQL con el esquema inicial de clients/projects/messages/finances.
PF-F-03historia
Aceptada

Como administrador, quiero un dashboard con KPIs y gestión de proyectos, clientes y finanzas

#crm#dashboard#fase-1Fase 1 · Fundación · Bootstrap del portfolio: Astro, auth y CRM base
  • Dashboard admin con KPIs de proyectos, mensajes, clientes y finanzas.
  • Sidebar de navegación agrupada y FinanceTable/MessagesList funcionales.
  • Formulario de contacto público con validación y persistencia de mensajes.
PF-CA-01historia
Aceptada

Como administrador, quiero backups automáticos de la base de datos para no perder información

#backups#cron#fase-2Fase 2 · CRM y auth · Backups, GitHub OAuth y rediseño del CRM
  • API de backups sube snapshots a Vercel Blob mediante cron programado.
  • Página /admin/backup lista y permite crear backups manualmente.
PF-CA-02historia
Aceptada

Como administrador, quiero iniciar sesión con GitHub en vez de usuario/contraseña

#auth#oauth#fase-2Fase 2 · CRM y auth · Backups, GitHub OAuth y rediseño del CRM
  • Proveedor Credentials reemplazado por GitHub Provider en Auth.js.
PF-CA-03historia
Aceptada

Como administrador, quiero un dashboard, sidebar y páginas de certificaciones con mejor UX

#ui#certificaciones#fase-2Fase 2 · CRM y auth · Backups, GitHub OAuth y rediseño del CRM
  • Dashboard, Sidebar, AdminLayout y contacto rediseñados con mejor jerarquía visual.
  • CertCard y la página de certificaciones muestran estado (vigente/expirada) correctamente.
PF-OB-01historia
Aceptada

Como administrador, quiero monitorear la salud de mis servicios en producción

#monitoreo#fase-3Fase 3 · Observabilidad · Monitoreo, encriptación de variables, dominios y presentaciones
  • Esquema monitors/monitor_checks/monitor_incidents con checks HTTP periódicos.
  • Página /admin/monitors con estado, latencia e incidentes por monitor.
  • 13 commits dedicados a monitoreo durante la iteración.
PF-OB-02historia
Aceptada

Como administrador, quiero que las variables de entorno de mis proyectos estén cifradas

#seguridad#cripto#fase-3Fase 3 · Observabilidad · Monitoreo, encriptación de variables, dominios y presentaciones
  • Utilidades de cifrado/descifrado (crypto.ts) para project_env_vars.
  • Revelado de secretos on-demand vía fetch, sin exponerlos en el HTML inicial.
PF-OB-03historia
Aceptada

Como administrador, quiero gestionar dominios y ver su estado DNS/SSL

#dominios#fase-3Fase 3 · Observabilidad · Monitoreo, encriptación de variables, dominios y presentaciones
  • Página /admin/domains con verificación de dominios (8 commits del periodo).
PF-OB-04historia
Aceptada

Como administrador, quiero un pipeline de seguimiento comercial (leads → propuesta → cierre) y briefings de cliente

#crm#seguimiento#fase-3Fase 3 · Observabilidad · Monitoreo, encriptación de variables, dominios y presentaciones
  • Página /admin/seguimiento con tablero de interacciones por proyecto.
  • Módulo de briefings con formulario e ítems asociados.
PF-OB-05historia
Aceptada

Como administrador, quiero presentar slides a clientes con control remoto

#slides#fase-3Fase 3 · Observabilidad · Monitoreo, encriptación de variables, dominios y presentaciones
  • presentations/presentation_slides con reveal.js.
  • Vistas /admin/slides/[id]/present y /control sincronizadas (8 commits).
PF-VS-04spike
Aceptada

Como administrador, quiero una demo read-only del panel admin para mostrar a reclutadores

#demo#fase-10Fase 4 · Vitrina y SEO · Vitrina pública, status page, EKG y capa técnica de SEO
  • Entregada en Fase 10 - ver PF-LD-02.
PF-SG-01historia
Aceptada

Como administrador, quiero un sensor que observe y clasifique requests hostiles sin bloquear tráfico legítimo

#seguridad#siem#fase-5Fase 5 · Seguridad · Micro-SIEM, rate limiting durable y blocklist
  • classify.ts clasifica requests por firmas conocidas de ataque.
  • sensor.ts observa cada request de forma síncrona y no bloqueante (fire-and-forget).
  • security_events y security_rollups agregan eventos para el panel.
PF-SG-02historia
Aceptada

Como administrador, quiero bloquear IPs maliciosas y aplicar rate limiting que sobreviva a un redeploy

#blocklist#rate-limit#fase-5Fase 5 · Seguridad · Micro-SIEM, rate limiting durable y blocklist
  • blocklist.ts responde 403 seco a IPs bloqueadas, con lectura cacheada 30s.
  • rate_limit_buckets: ratelimit-durable.ts reemplaza el rate limiting en memoria (9 commits).
  • Todo el bloque de enforcement es fail-open: un fallo nunca tumba el sitio.
  • Tests de blocklist y clasificación de seguridad en tests/.
PF-SG-03historia
En desarrollo

Como administrador, quiero anomalías de seguridad agregadas en un panel para revisión periódica

#anomalías#fase-5Fase 5 · Seguridad · Micro-SIEM, rate limiting durable y blocklist
  • security_anomalies almacena desviaciones detectadas sobre los rollups.
  • ·Panel /admin/security con vista consolidada de anomalías y acciones de respuesta.
PF-PL-01historia
Aceptada

Como administrador, quiero registrar y gestionar mis llaves de seguridad desde el panel

#webauthn#passkey#fase-8Fase 8 · Login passwordless · Login sin contraseña con llaves de seguridad (WebAuthn/FIDO2)
  • Tabla webauthnCredentials (credentialID, publicKey, counter, transports, nickname) con índice por login.
  • /admin/passkeys lista, añade (con nickname) y revoca llaves; excludeCredentials evita re-registrar la misma llave física.
  • API /api/admin/webauthn/{registration,credentials} protegida por el gate de sesión+allowlist existente.
PF-PL-02historia
Aceptada

Como administrador, quiero entrar a /admin tocando mi llave, sin pasar por GitHub

#webauthn#passkey#auth#fase-8Fase 8 · Login passwordless · Login sin contraseña con llaves de seguridad (WebAuthn/FIDO2)
  • Flujo usernameless (sin allowCredentials): el navegador ofrece las llaves discoverable del rpID y el login se descubre por el credentialID devuelto.
  • Proof HMAC de 30s (signPasskeyProof/verifyPasskeyProof) conecta la ceremonia FIDO2 con el provider "passkey" de Auth.js, sin repetir la criptografía ahí.
  • rpID/origin derivados del Host de cada request (prod, previews de Vercel y dev en cualquier puerto), no hardcodeados.
PF-PL-03bug
Cola

Como administrador, quiero que el selector de llaves del navegador distinga cada YubiKey por su nombre

#webauthn#passkey#ux#pendienteFase 8 · Login passwordless · Login sin contraseña con llaves de seguridad (WebAuthn/FIDO2)
  • ·Detectado en uso real (2026-07-12): con 2+ llaves registradas, el diálogo nativo "Choose a passkey" de Chrome muestra "mikerb95 / USB security key" repetido para cada una, en vez del nickname (YubiKey 1, YubiKey 2) - porque userDisplayName se fija en generateRegistrationOptions con el login, no con un nombre por llave, y queda grabado en el hardware al registrar.
  • ·Fix: pasar un userDisplayName distinto por llave (ej. incluir el nickname) en buildRegistrationOptions, y re-registrar las llaves existentes para que tomen el nuevo nombre - el cambio no aplica retroactivo a credenciales ya grabadas.
PF-LD-02historia
Aceptada

Como administrador, quiero una demo read-only del panel admin para mostrar a reclutadores sin exponer datos reales

#demo#seguridad#fase-10Fase 10 · Lab de experimentos y demo pública · Laboratorio de experimentos CI/CD y demo read-only del admin
  • /demo firma un token de sesión de solo lectura y lo valida en middleware sin tocar Auth.js.
  • Middleware bloquea cualquier método no-GET en modo demo y marca el flag demo en locals.
  • scripts/seed-demo.mjs siembra clientes, proyectos, finanzas, monitores y CI runs ficticios en una base aislada.
  • Tests de verificación de token demo y restricción de métodos.
PF-LD-03tarea
Aceptada

Como administrador, quiero que la presentación privada del deck no sea accesible desde la demo pública

#seguridad#demo#fase-10Fase 10 · Lab de experimentos y demo pública · Laboratorio de experimentos CI/CD y demo read-only del admin
  • Middleware distingue isPrivate de isAdmin para aplicar headers de seguridad correctos.
  • Acceso al deck de presentación restringido a sesión de administrador real, excluyendo la sesión demo.
PF-PC-03historia
Aceptada

Como administrador, quiero cobrarle a un cliente por WhatsApp con un enlace de pago corto, sin que necesite cuenta

#cobros#whatsapp#pagos#fase-11Fase 11 · Portal de clientes · Portal autenticado de clientes: facturación, cobros por WhatsApp y comunicación
  • Página /cobrar genera un cobro con código corto (alfabeto/crypto propios) y arma el mensaje de WhatsApp.
  • /pagar simula el pago del cobro validando titularidad de la factura, reutilizando la máquina de estados de payments.
  • Webhook de conciliación liquida o reversa el pago y actualiza la factura asociada.
  • Cron diario (sweep) marca facturas vencidas y notifica al cliente automáticamente.
  • Tests de cálculo de facturas, formato de dinero en COP y expiración de cobros.
PF-PG-01historia
Aceptada

Como administrador, quiero activar clientes en el portal, invitar usuarios y gestionar sus facturas e hitos desde /admin

#portal#admin#fase-12Fase 12 · Gestión del portal y QA end-to-end · Administración del portal (equipo, facturas, hitos, documentos) y arnés de pruebas E2E
  • /admin/portal activa clientes, invita usuarios y lista su estado (invited/active/disabled).
  • /admin/portal/facturas y /admin/portal/hitos con CRUD completo de invoices y milestones.
  • /admin/portal/mensajes lista y responde hilos de conversación por cliente, con notificación al responder.
  • Enlaces añadidos al sidebar de administración.
PF-SA-01historia
Aceptada

Como administrador, quiero que cada push escanee vulnerabilidades de dependencias y del propio código

#sast#seguridad#fase-14Fase 14 · SAST, dependencias y accesibilidad · Escaneo de seguridad (CodeQL/npm audit) y accesibilidad (axe-core) integrados al LAB
  • .github/workflows/security.yml corre npm audit y CodeQL en cada push/PR.
  • scripts/npm-audit-scan.mjs normaliza el reporte de npm audit para ingesta.
  • security_findings agrega hallazgos por herramienta con severidad, estado y auto-resolución cuando el hallazgo desaparece.
PF-SA-02historia
Aceptada

Como administrador, quiero saber si las páginas públicas cumplen accesibilidad básica (axe-core)

#a11y#fase-14Fase 14 · SAST, dependencias y accesibilidad · Escaneo de seguridad (CodeQL/npm audit) y accesibilidad (axe-core) integrados al LAB
  • scripts/a11y-scan.mjs recorre páginas públicas con Playwright + @axe-core/playwright.
  • .github/workflows/a11y.yml ejecuta el escaneo en CI y sube resultados al ingest.
  • Umbrales de contraste de color ajustados tras los primeros hallazgos reales.
PF-LM-01historia
Aceptada

Como administrador, quiero saber si mis tests realmente detectan bugs (mutation testing), no solo si pasan

#mutation#testing#fase-16Fase 16 · LAB Fase 7: mutation testing y contract testing · Stryker (mutation score) y pruebas de contrato de API en el pipeline
  • stryker.config.json configura mutation testing sobre los módulos críticos, con reporte HTML y concurrencia ajustada.
  • .github/workflows corre Stryker y scripts/mutation-scan reporta el score al panel LAB (mutationScore en ci_runs).
  • Pipeline y /lab muestran el mutation score cuando hay un resultado reciente disponible.
PF-LM-02historia
Aceptada

Como administrador, quiero pruebas de contrato que fallen si un endpoint cambia su forma de respuesta sin querer

#contract-testing#fase-16Fase 16 · LAB Fase 7: mutation testing y contract testing · Stryker (mutation score) y pruebas de contrato de API en el pipeline
  • Esquemas zod (health, checkout, status/latencia, SLO) definen la forma esperada de cada respuesta.
  • tests/contracts.test.ts valida los endpoints clave contra esos esquemas.
  • Roadmap actualizado: etapas 1–6 marcadas como completadas.
PF-IP-01historia
Aceptada

Como administrador, quiero ver el portal exactamente como lo ve un cliente, para dar soporte sin pedirle su clave

#impersonación#soporte#fase-18Fase 18 · Impersonación de soporte y facturas en PDF · "Ver como cliente" desde /admin y descarga de facturas en PDF
  • Botón "Ver como cliente" en la lista de clientes con usuarios de portal activos.
  • API de impersonación crea una portal_session marcada con impersonatedBy, visible en PortalLayout con aviso y logout que restaura la sesión admin.
  • Modo impersonado restringido a solo lectura: bloquea pagos y cualquier acción de escritura; queda registrado en auditoría (impersonate.start/end).
PF-CV-02historia
Aceptada

Como administrador, quiero ver quién descargó mi CV y detectar revisitas del mismo dispositivo

#cv#admin#seguridad#fase-21Fase 21 · Descarga de CV con huella y auditoría · Descarga de CV con token de un solo uso, fingerprint y panel de estadísticas
  • cv-downloads.ts reutiliza el deviceHash del recolector de fingerprinting; sin TTL, a diferencia de las salas de la demo.
  • Revisitas del mismo deviceHash actualizan la fila existente (contador revisits) en vez de crear duplicados.
  • /admin/lab/cv-downloads y su API listan el historial completo con IP, UA y referer.
PF-LE-02historia
Aceptada

Como administrador, quiero que una IP reincidente reciba un bloqueo cada vez más largo, no siempre el mismo TTL

#seguridad#blocklist#fase-22Fase 22 · Rutas de aprendizaje y bloqueo escalado de IPs · Open Security Labs con progreso persistente, IP blocking escalado y fixes de revisitas en fingerprinting
  • blockIpEscalated calcula TTL creciente (1h → 24h → 7d) según el historial de bloqueos previos de la IP.
  • Honeypots tocados se bloquean inline desde el middleware, sin esperar al cron de auto-block.
  • Tests unitarios de blockIpEscalated y de la lógica de TTL en isBlocked.
PF-DA-01historia
Aceptada

Como administrador, quiero que la aplicación corriendo también se ataque de forma automatizada, no solo se lea el código

#seguridad#lab#ci#fase-25Fase 25 · DAST con OWASP ZAP · Análisis dinámico de seguridad contra el preview, ingerido al panel del LAB
  • Workflow dast.yml corre el baseline de OWASP ZAP contra el preview deployment, con guard para no tocar producción.
  • parseZapReport convierte el reporte JSON en hallazgos, reutilizando el fingerprint de deduplicación existente en vez de una tabla nueva.
  • Tests del parser sobre reportes reales (tests/findings.test.ts).
  • DAST incorporado como nivel propio en el inventario de pruebas y en la clasificación de V&V.
PF-DW-02tarea
Aceptada

Como administrador, quiero presentarme por WhatsApp y dejar agendar una llamada sin cruzar correos

#negocio#herramientas#fase-26Fase 26 · Pipeline en vivo y captación de clientes no técnicos · Estado real del pipeline en /docs y landing comercial de diseño web
  • Constructor de mensajes de WhatsApp para presentaciones rápidas.
  • Enlace de agenda directa en /contact, junto al formulario.

Como stakeholder académico (4)

PF-CA-04tarea
Aceptada

Como stakeholder académico, quiero documentación de requerimientos funcionales y user stories

#documentación#fase-2Fase 2 · CRM y auth · Backups, GitHub OAuth y rediseño del CRM
  • Documento de requerimientos funcionales para gestión de proyectos y clientes.
  • User stories de visitantes públicos y funcionalidades de administrador.
PF-DP-01historia
Aceptada

Como stakeholder académico, quiero navegar la documentación del proyecto sin necesitar sesión de administrador

#documentación#público#fase-9Fase 9 · Documentación pública · Docs académicas fuera de /admin, trazabilidad de requisitos y deck de presentación
  • Páginas de casos de uso, diagramas, historias de usuario, requisitos y kanban migradas de /admin/docs a /docs.
  • DocsNav como componente de navegación propio, reemplazando AdminLayout en todas las vistas de documentación.
  • Redirect catch-all de /admin/docs a /docs para no romper enlaces existentes.
PF-DP-02historia
Aceptada

Como stakeholder académico, quiero ver cada requisito con su verificación, notas y requisitos relacionados

#requisitos#trazabilidad#fase-9Fase 9 · Documentación pública · Docs académicas fuera de /admin, trazabilidad de requisitos y deck de presentación
  • Interfaz Requisito ampliada con campos de verificación, notas técnicas e ítems relacionados.
  • Modal de detalle por ítem en RequisitosView con atributos de datos para accesibilidad.
  • Diagramas Mermaid (casos de uso, secuencia, clases, componentes) con tema propio y mejor contraste.
PF-DP-03historia
Aceptada

Como stakeholder académico, quiero un deck de presentación que resuma el proyecto para la sustentación

#presentación#fase-9Fase 9 · Documentación pública · Docs académicas fuera de /admin, trazabilidad de requisitos y deck de presentación
  • /docs/presentacion.astro consolida arquitectura, fases y decisiones clave del proyecto.
  • Enlace al deck desde DocsNav y desde la documentación principal.

Como visitante técnico (4)

PF-EN-01historia
Aceptada

Como visitante técnico, quiero un panel público con métricas de ingeniería reales (Web Vitals, CI, disponibilidad)

#engineering#observabilidad#público#fase-6Fase 6 · Panel de ingeniería · Página pública de ingeniería con métricas verificables y prueba de vida
  • /engineering muestra Core Web Vitals p75 de usuarios reales (RUM) con p50/p95, distribución de rating, tendencia 7d y peor ruta por métrica.
  • Cards de pipeline CI (tests, cobertura, duración) y disponibilidad agregada, alimentadas de ci_runs y monitor_checks.
  • CardPopover en cada métrica explica el origen del dato y el umbral contra el que se evalúa; página server-rendered con datos de producción.
PF-EN-02historia
En aceptación

Como visitante técnico, quiero comprobar que las métricas de /engineering están vivas y no hardcodeadas

#engineering#verificación#fase-6Fase 6 · Panel de ingeniería · Página pública de ingeniería con métricas verificables y prueba de vida
  • Endpoint /api/engineering/live devuelve marcas de tiempo frescas (última muestra RUM, último sondeo, último run CI) más el reloj del servidor.
  • Las cards consultan la prueba de vida al abrirse e indican en vivo la frescura; solo expone metadatos, nunca URLs internas ni configuración.
  • ·Merge del PR #2 a main y despliegue a producción de la verificación en vivo.
PF-LD-01historia
Aceptada

Como visitante técnico, quiero ver un laboratorio con los experimentos de CI/CD y su resultado más reciente

#lab#ci#público#fase-10Fase 10 · Lab de experimentos y demo pública · Laboratorio de experimentos CI/CD y demo read-only del admin
  • /lab lista experimentos con conteo de runs y fecha del último, alimentado por ci_runs.
  • Enlace "Laboratorio" en footer y navbar, y desde el caso de estudio de tools.
  • Ruta /lab añadida a STATIC_PATHS del sitemap.
PF-SA-03historia
Aceptada

Como visitante técnico, quiero ver en /lab si hay hallazgos abiertos de seguridad o accesibilidad

#lab#seguridad#a11y#fase-14Fase 14 · SAST, dependencias y accesibilidad · Escaneo de seguridad (CodeQL/npm audit) y accesibilidad (axe-core) integrados al LAB
  • /admin/lab/security lista hallazgos con filtro por estado y acción de marcar resuelto (API GET/PATCH).
  • /lab muestra card de seguridad y accesibilidad condicionada a que exista ingesta reciente, con conteo agregado por estado.
  • Tests de procesamiento de hallazgos y transición de estados.

Como responsable del sitio (1)

PF-FP-03historia
En aceptación

Como responsable del sitio, quiero que la demo sea ética y segura: efímera, consentida y con defensas anti-abuso

#fingerprint#privacidad#seguridad#fase-7Fase 7 · Lab educativo · Laboratorio de fingerprinting en vivo (Sala de espejos)
  • Salas efímeras: TTL de 2h purgadas por el cron (sweepFpRooms), sin PII persistente; consentimiento explícito antes de recolectar.
  • Rate limiting durable por endpoint (beat reescopado por dispositivo para eventos con muchos móviles tras una NAT).
  • entropyBits acotado a 0–64 en servidor y valores escapados en el DOM (el UA es controlable).
  • Cierre pedagógico: por qué el incógnito no protege y cómo defenderse (Tor, resistFingerprinting).

Como cliente (7)

PF-PC-01historia
Aceptada

Como cliente, quiero iniciar sesión en mi propio portal con invitación previa y recuperar mi contraseña si la olvido

#portal#auth#fase-11Fase 11 · Portal de clientes · Portal autenticado de clientes: facturación, cobros por WhatsApp y comunicación
  • client_users, client_invitations y portal_sessions con hashing scrypt y sesiones opacas revocables (cookie portal_session, distinta de admin).
  • APIs de login, logout, aceptar invitación y reset de contraseña, con rate limiting y logging al micro-SIEM.
  • PortalAuthLayout para las pantallas de login, invitación y reset; requirePortalSession() como única puerta de entrada al tenant.
  • Tests de hashing de contraseña, clasificación de rutas del portal y aislamiento entre tenants.
PF-PC-02historia
Aceptada

Como cliente, quiero ver el estado de mis proyectos, salud del servicio y mis facturas en un panel propio

#portal#dashboard#fase-11Fase 11 · Portal de clientes · Portal autenticado de clientes: facturación, cobros por WhatsApp y comunicación
  • Página de overview del proyecto con HealthCard (salud de monitores) y MilestoneTimeline (hitos con estado).
  • Selector de proyecto (tabs) cuando el cliente tiene más de uno, resuelto por ?p= solo contra la lista de proyectos de su propia sesión - un id ajeno cae al primero propio.
  • Módulo invoices/invoice_items con CRUD completo, numeración correlativa y estados (draft/sent/paid/overdue/void).
  • Centro de notificaciones in-app e hilos de mensajería (portal_threads/portal_messages) con conteo de no leídos.
PF-PG-02historia
Aceptada

Como cliente, quiero gestionar mi cuenta, mi equipo, mis documentos y ver mi historial de pagos

#portal#cuenta#documentos#fase-12Fase 12 · Gestión del portal y QA end-to-end · Administración del portal (equipo, facturas, hitos, documentos) y arnés de pruebas E2E
  • /portal/cuenta con perfil, cambio de contraseña y gestión de sesiones activas.
  • Gestión de equipo (invitar/roles) reutilizando client_invitations desde el propio cliente.
  • /portal/documentos sube y descarga archivos vía stream autenticado (se descartó URL firmada por seguridad) con auditoría.
  • /mis-pagos resuelve el historial por teléfono con enlace firmado y rate limiting.
PF-PG-03historia
Aceptada

Como cliente, quiero pagar un cobro real por WhatsApp y recibir una notificación cuando se apruebe

#pagos#wompi#notificaciones#fase-12Fase 12 · Gestión del portal y QA end-to-end · Administración del portal (equipo, facturas, hitos, documentos) y arnés de pruebas E2E
  • Checkout API en /api/c/[code]/checkout.ts integra Wompi para el cobro real, además del mock de pruebas.
  • notifyCobroPaid envía alerta push al admin cuando un cobro se marca pagado.
  • Rate limiting propio para las rutas de enlace de cobro (isCobroLinkPath).
PF-IP-02historia
Aceptada

Como cliente, quiero descargar mi factura en PDF para mi contabilidad

#facturas#pdf#fase-18Fase 18 · Impersonación de soporte y facturas en PDF · "Ver como cliente" desde /admin y descarga de facturas en PDF
  • /api/portal/facturas/[id]/pdf genera el PDF de la factura al vuelo con pdf-lib.
  • Enlace de descarga de PDF añadido a cada factura en el portal del cliente.
PF-PV-01historia
Aceptada

Como cliente, quiero ver la respuesta a mi mensaje sin recargar la página

#portal#tiempo-real#fase-31Fase 31 · El portal deja de estar congelado en el instante del SSR · Digest en vivo, campana de notificaciones y feed de actividad por proyecto
  • portalLiveDigest() sobre los helpers existentes: cero SQL nuevo.
  • GET /api/portal/live con rate limit por sesión (10/min) y no-store.
  • Ciclo de 20 s con pausa por visibilidad y backoff 20→300 s; fail-open silencioso.
  • Un CustomEvent y tres suscriptores: campana, dashboard e hilo abierto.
  • tests/portal-live.test.ts con libSQL real: aislamiento entre clientes, rol billing sin mensajes, projectId ajeno cae al propio.
PF-PV-02historia
Aceptada

Como cliente, quiero una línea de tiempo de lo que ha pasado en mi proyecto

#portal#tiempo-real#fase-31Fase 31 · El portal deja de estar congelado en el instante del SSR · Digest en vivo, campana de notificaciones y feed de actividad por proyecto
  • Migración aditiva de portal_activity con sus índices; clientId denormalizado para no depender de un JOIN.
  • recordActivity() fire-and-forget cableado en los cinco puntos que ya notificaban; nunca lanza.
  • Feed en /portal (últimas 15) y /portal/actividad con filtro y paginación por cursor.
  • Las entradas se apagan desde /admin/portal/actividad en vez de borrarse.
  • tests/portal-activity.test.ts: aislamiento, cursor que no repite ni salta filas, interruptor de visibilidad.

Como visitante de la demo (1)

PF-PC-04tarea
Aceptada

Como visitante de la demo, quiero explorar el portal de clientes sin poder pagar ni modificar nada real

#demo#portal#fase-11Fase 11 · Portal de clientes · Portal autenticado de clientes: facturación, cobros por WhatsApp y comunicación
  • Rutas de pago bloqueadas explícitamente en modo demo, incluso con sesión de solo lectura válida.
  • Enlace al portal/demo del panel P&L añadido al caso de estudio de tools y al login.
  • README documenta el módulo de portal y cobros junto a demo y lab.

Como equipo de QA (2)

PF-PG-04tarea
Aceptada

Como equipo de QA, quiero un arnés de pruebas end-to-end contra bases de datos desechables

#testing#e2e#playwright#fase-12Fase 12 · Gestión del portal y QA end-to-end · Administración del portal (equipo, facturas, hitos, documentos) y arnés de pruebas E2E
  • Playwright configurado con fixtures propios y script para crear/sembrar bases de datos desechables por corrida.
  • e2e/demo.spec.ts valida acceso y aislamiento de datos de la demo; suite de páginas públicas y headers de seguridad.
  • webServer de Playwright siembra la base antes de levantar el servidor de pruebas.
PF-EC-01historia
Aceptada

Como equipo de QA, quiero que las pruebas E2E corran automáticamente en cada push, no solo en mi máquina

#e2e#ci#fase-13Fase 13 · E2E en CI y saneamiento de entorno · Playwright integrado al pipeline y unificación de variables de entorno
  • Job de Playwright añadido a .github/workflows/ci.yml, corriendo contra base de datos desechable sembrada.
  • Roadmap actualizado marcando el E2E de Playwright como completado, con siguientes pasos definidos.

Como desarrollador (3)

PF-EC-02tarea
Aceptada

Como desarrollador, quiero un único punto de acceso a variables de entorno que funcione igual en Astro, scripts y tests

#entorno#refactor#fase-13Fase 13 · E2E en CI y saneamiento de entorno · Playwright integrado al pipeline y unificación de variables de entorno
  • serverEnv() en src/lib/env.ts unifica el acceso a import.meta.env/process.env; checkout, cobros y mis-pagos migrados.
  • .env.local y variantes locales (.bak incluido) excluidas de git para evitar fugas de credenciales de Wompi/Turso.
  • Tests E2E de checkout (con idempotencia) y de formulario de contacto (validación y rate limiting) con IPs únicas por caso.
PF-PV-02tarea
Aceptada

Como desarrollador, quiero un único parser de tech stack para no repetir lógica de formato en cada vista de proyecto

#refactor#proyectos#fase-20Fase 20 · Pulido visual y saneamiento de tech stack · Fondo con profundidad (blobs), separación de navbar y parser único de tech stack
  • parseTechStack maneja tanto JSON como texto plano de forma tolerante.
  • ProjectCard, index y [id].astro migrados al parser único, eliminando JSON.parse directo.
PF-DK-01historia
Aceptada

Como desarrollador, quiero que clonar el repositorio produzca el mismo entorno en cualquier máquina

#infraestructura#docker#fase-33Fase 33 · Las notaciones que Mermaid no dibuja, y el entorno como código · Diagramas UML de despliegue, comunicación, actividades y componentes con motor propio; devcontainer y libSQL en contenedor
  • .devcontainer/ con Node 22.12 exacto, Chromium de Playwright preinstalado y usuario no-root.
  • Imágenes pineadas por digest, no por tag: una reproducibilidad que depende de que nadie mueva latest no lo es.
  • compose.yaml levanta dos servidores sqld (principal y demo), como en producción, con npm run db:up.
  • Contenedores con cap_drop ALL y solo las capacidades medidas como imprescindibles.
  • Documentado que Docker no es ni debe ser el runtime de producción: contenerizar la app perdería edge, previews y rollback automático.

Como asistente a la charla (1)

PF-PZ-01historia
Aceptada

Como asistente a la charla, quiero una landing con la agenda y la forma de contactar al ponente

#platziconf#landing#fase-19Fase 19 · Charla Platzi Conf y presentaciones públicas · Landing de la charla y presentaciones (slides) con estado en vivo
  • /platziconf con tema visual propio (platzi-theme) y CTA a Calendly.
  • Fondo full-bleed consistente en pantallas anchas.

Como asistente (2)

PF-PZ-02historia
Aceptada

Como asistente, quiero ver el estado de la presentación (slide actual) sin tener sesión de administrador

#slides#público#fase-19Fase 19 · Charla Platzi Conf y presentaciones públicas · Landing de la charla y presentaciones (slides) con estado en vivo
  • API de estado de presentación expuesta sin requerir sesión admin, consumida por la vista de presentación.
  • Botón para copiar el enlace de la slide actual al portapapeles desde /admin/slides.
PF-CP-02historia
Aceptada

Como asistente, quiero entrar al material de mi grupo sin crear otra cuenta

#capacitacion#seguridad#fase-36Fase 36 · Capacitación en IA como línea de negocio · Banco de recursos con acceso por código de grupo y landing de capacitación
  • Código de grupo que se dicta al cerrar la sesión, con alfabeto sin caracteres ambiguos (sin O/0, I/1/l, S/5) y normalizado al comparar; se canjea por un pase firmado de 30 días, sin correo ni cuenta.
  • El id del código viaja dentro de lo firmado y se revalida contra la base en cada request: revocar corta el acceso de esa cohorte al instante, sin tocar el de las demás.
  • Único punto del repo que falla CERRADO: sin poder confirmar que el código sigue vivo se cae al banco público, porque abrir publicaría material restringido en una respuesta cacheable.
  • El canje devuelve el mismo mensaje para código inexistente, vencido, revocado o mal escrito, y lleva rate limit propio (10/min por IP) sobre el mismo enforcement durable de los links de cobro.
  • tests/capacitacion.test.ts: 35 casos. Firma con otro secreto, sin secreto, vencimiento reescrito, id de cohorte reescrito y tokens malformados, todos rechazados sin lanzar.

Como visitante que revisita la sala de fingerprinting (1)

PF-LE-03bug
Aceptada

Como visitante que revisita la sala de fingerprinting, quiero que el tablero me reconozca aunque el hash de la librería de referencia cambie

#fingerprint#bug#fase-22Fase 22 · Rutas de aprendizaje y bloqueo escalado de IPs · Open Security Labs con progreso persistente, IP blocking escalado y fixes de revisitas en fingerprinting
  • joinDevice usa el ID único de dispositivo (no la etiqueta) para decidir si es una revisita, y ya no depende de que libFpHash coincida exactamente.
  • Tests con distintos escenarios de libFpHash (coincide, cambia, ausente) validando que la revisita se reconoce igual.

Como compañero de clase (1)

PF-DT-01historia
Aceptada

Como compañero de clase, quiero un único punto de entrada que me explique cómo se prueba este sistema

#documentación#testing#público#fase-24Fase 24 · Documentación de pruebas y V&V · Guía pública del testing, verificación y validación, y diagrama de paquetes
  • /docs/testing cubre los niveles de prueba, la pirámide con volúmenes reales, el pipeline etapa por etapa y un glosario.
  • Las métricas salen de src/data/testing.ts y de la ingesta del pipeline, no se escriben a mano en la página.
  • Restricción OPSEC respetada: los tests de seguridad se describen por lo que garantizan, sin citar patrones, rutas señuelo ni umbrales.

Como evaluador (3)

PF-DT-02historia
Aceptada

Como evaluador, quiero ver el testing clasificado bajo el marco de verificación y validación

#documentación#testing#fase-24Fase 24 · Documentación de pruebas y V&V · Guía pública del testing, verificación y validación, y diagrama de paquetes
  • /docs/verificacion-validacion reclasifica los niveles bajo V&V con niveles de integridad y procesos del ciclo de vida.
  • src/data/vyv.ts referencia los niveles de testing.ts por id en vez de duplicarlos, y un test verifica esa integridad referencial.
PF-DT-03tarea
Aceptada

Como evaluador, quiero el diagrama de paquetes que faltaba en la documentación UML

#documentación#uml#fase-24Fase 24 · Documentación de pruebas y V&V · Guía pública del testing, verificación y validación, y diagrama de paquetes
  • /docs/diagrama-paquetes con la representación UML de los paquetes del sistema y su versión ilustrada.
  • Pestaña «Paquetes» añadida a DocsNav.
PF-UML-01historia
Aceptada

Como evaluador, quiero ver la vista de red y las interacciones en notación UML de verdad

#documentación#uml#fase-33Fase 33 · Las notaciones que Mermaid no dibuja, y el entorno como código · Diagramas UML de despliegue, comunicación, actividades y componentes con motor propio; devcontainer y libSQL en contenedor
  • Diagrama de despliegue con nodos «device»/«executionEnvironment», artefactos y caminos de comunicación con su protocolo.
  • Cuatro diagramas de comunicación con numeración decimal, enlazados en ambos sentidos con los de secuencia.
  • Tres diagramas de actividades con particiones, bifurcación concurrente y bucle de reintento.
  • SVG generado en el servidor desde modelos tipados; el navegador no ejecuta JavaScript para dibujarlos.

Como dueño de un negocio local (1)

PF-DW-01historia
Aceptada

Como dueño de un negocio local, quiero entender qué me ofrecen y cuánto cuesta sin lenguaje técnico

#negocio#público#fase-26Fase 26 · Pipeline en vivo y captación de clientes no técnicos · Estado real del pipeline en /docs y landing comercial de diseño web
  • /paginas-web con tres planes de precio visible, perfiles de cliente, pasos del proceso y FAQ.
  • Contacto por WhatsApp o formulario, reutilizando /api/contact con su rate limiting ya probado.
  • Enlace «Diseño Web» en el navbar; la landing vive aparte de la marca técnica del resto del sitio.

Como cliente que navega con teclado o lector de pantalla (1)

PF-PA-01historia
Aceptada

Como cliente que navega con teclado o lector de pantalla, quiero saber qué pasó al enviar un formulario del portal

#accesibilidad#portal#fase-27Fase 27 · Accesibilidad del portal y capa de movimiento · Salto al contenido, anuncios en vivo y foco explícito; scroll suave con Lenis y GSAP
  • Skip link como primer elemento tabulable del portal, con el <main> identificado como destino.
  • Región aria-live que anuncia el resultado del envío, incluidos los mensajes de error explícitos.
  • El foco aterriza en la confirmación tras enviar, en vez de quedarse donde estaba.

Como jurado (3)

PF-BP-01historia
Aceptada

Como jurado, quiero ver los procesos de negocio modelados en BPMN, no descritos en prosa

#documentación#bpmn#público#fase-28Fase 28 · Procesos de negocio en BPMN y documento de arquitectura · Motor de diagramas BPMN propio, versión imprimible y DEA
  • /docs/diagrama-bpmn renderiza cuatro procesos (monitoreo, cobro de campo, acceso al portal, seguridad) desde datos tipados en src/data/bpmn.ts.
  • src/lib/bpmn-layout.ts calcula carriles, canales de transición y cajas de etiqueta como lógica pura; 83 tests en tests/bpmn.test.ts.
  • Detección de colisiones de etiquetas y de texto fuera de los límites dentro del propio motor de layout.
  • Eventos temporizadores de frontera con su tabla de tiempos por proceso.
PF-EP-01historia
Aceptada

Como jurado, quiero que las cifras de /docs/testing sean la corrida real, no un número escrito a mano

#testing#documentacion#fase-39Fase 39 · La evidencia de testing deja de vivir solo en la terminal · Instantánea de la corrida real, referencia de reporters y hallazgos de k6 publicados
  • scripts/report-tests.mjs lee el XML JUnit de "npx vitest run --reporter=junit" y genera src/data/ejecucion-pruebas.json (versionado, porque coverage/ e informes/ están en .gitignore y Vercel no puede leer lo que no está en el repo) más un informe HTML autocontenido.
  • /docs/ejecucion-pruebas publica el total real de la última regeneración (1181 tests y 0 fallos en la entrega del 21 ago; 1200 en 70 archivos tras regenerarla el 26 ago), duración por nivel, distribución logarítmica de tiempos y las 12 pruebas más lentas.
  • METRICAS_REFERENCIA, NIVELES y PIRAMIDE en src/data/testing.ts pasan a derivarse de la instantánea (EJECUCION) en vez de tener sus propios números, que era justo la fuente de la contradicción (724 vs 777 tests en dos tablas distintas del mismo documento).
PF-DR-01historia
Aceptada

Como jurado, quiero ver qué zona puede alcanzar a cuál y con qué protocolo, no solo dónde corre cada nodo

#diagramas#seguridad#fase-40Fase 40 · La pregunta que el diagrama de despliegue no responde · Diagrama de red por zonas de confianza
  • src/data/red.ts modela zonas (con nivel de confianza), hosts y flujos dirigidos; src/lib/red-layout.ts calcula la geometría reutilizando el motor genérico del BPMN (corte de texto, polilíneas redondeadas).
  • NetworkDiagram.astro renderiza el SVG en el servidor; /docs/diagrama-red lo publica con la tabla de controles por cruce de frontera.
  • OPSEC respetado: solo entra lo ya público (puertos estándar, protocolos, proveedores y controles por categoría), nunca umbrales de rate limit ni nombres de reglas de detección.

Como sustentante (1)

PF-BP-02tarea
Aceptada

Como sustentante, quiero entregar los diagramas en papel sin perder legibilidad

#documentación#bpmn#fase-28Fase 28 · Procesos de negocio en BPMN y documento de arquitectura · Motor de diagramas BPMN propio, versión imprimible y DEA
  • /docs/bpmn-imprimible con portada, un proceso por página y diagramas en vertical.
  • scripts/export-bpmn.mjs exporta cada proceso a SVG y PNG en docs/diagramas-bpmn/.
  • Documento de arquitectura (DEA) y taller de testing de caja negra actualizados junto a los diagramas.

Como visitante internacional (1)

PF-I18-01historia
Aceptada

Como visitante internacional, quiero leer el sitio en inglés sin perder la página en la que estoy

#i18n#público#seo#fase-29Fase 29 · Internacionalización del sitio público · Versión en inglés bajo /en sin duplicar páginas ni abrir bypasses
  • Prefijo /en con el español como idioma canónico sin prefijo; el selector de idioma conserva la página actual.
  • Siete páginas de marca traducidas vía diccionario: home, engineering, tools, security, contact, certifications y architecture.
  • Una sola implementación por página: la variante /en es un cascarón que reexporta la misma página y el locale sale de la URL del request.
  • hreflang recíproco con x-default, canónico localizado, og:locale y feed propio /en/rss.xml.
  • Sugerencia de idioma por Accept-Language como invitación descartable, nunca como mecanismo de ruteo (rompería el cache público).

Como responsable del sistema (1)

PF-I18-02historia
Aceptada

Como responsable del sistema, quiero que ningún guarda de seguridad cambie de veredicto por un prefijo de idioma

#i18n#seguridad#middleware#fase-29Fase 29 · Internacionalización del sitio público · Versión en inglés bajo /en sin duplicar páginas ni abrir bypasses
  • El middleware normaliza el pathname una sola vez, antes de cualquier clasificación de amenazas o de auth.
  • Las rutas privadas (admin, API, portal, cobros y los tres gates de login) devuelven 404 bajo cualquier prefijo de idioma.
  • 141 tests en tests/i18n-routing-guards.test.ts: cada guarda da el mismo veredicto para /x y /en/x, con casos adversariales (//en/admin, /EN/admin, /e%6E/admin, /english/algo).

Como traductor del sitio (1)

PF-I18-04tarea
Aceptada

Como traductor del sitio, quiero que falte una clave rompa el build y no la página

#i18n#calidad#fase-29Fase 29 · Internacionalización del sitio público · Versión en inglés bajo /en sin duplicar páginas ni abrir bypasses
  • en.ts declarado con satisfies sobre el diccionario español: astro check falla si falta un par.
  • tests/i18n-dictionary.test.ts detecta claves huérfanas y valores en inglés idénticos al español.
  • src/i18n/format.ts centraliza fechas, números y moneda por locale, con COP explícito para que no se lea como dólares.

Como visitante de /status (1)

PF-LT-01historia
Aceptada

Como visitante de /status, quiero que la página no pague una consulta por monitor para pintar la latencia

#rendimiento#observabilidad#público#fase-30Fase 30 · Coste de las consultas de /status y demo encendida · Índices, lectura por lotes dentro del techo de Turso y siembra de la demo
  • recentLatency lee el historial de todos los monitores por lotes, no uno por consulta.
  • Índices compuestos en monitor_checks (monitorId, at) y en ci_runs (createdAt), con migración aditiva.
  • Cache-Control ajustado en /api/status/latency.
  • tests/latency.test.ts cubre el techo de 50 términos por compound SELECT de Turso y los ids duplicados.

Como cliente con lector de pantalla (1)

PF-PV-03tarea
Aceptada

Como cliente con lector de pantalla, quiero enterarme de lo que cambia solo

#portal#accesibilidad#fase-31Fase 31 · El portal deja de estar congelado en el instante del SSR · Digest en vivo, campana de notificaciones y feed de actividad por proyecto
  • La región aria-live existente anuncia también lo que llega por el digest.
  • motion-reduce en la barra de avance.
  • Guard de demo: el digest late en modo demo pero leyendo de la base de demo, con casos en tests/portal-demo.test.ts, tests/portal-paths.test.ts y un e2e.

Como visitante anglófono (2)

PF-I18-05historia
Aceptada

Como visitante anglófono, quiero que las páginas de producto y estado estén en mi idioma, no solo la portada

#i18n#público#fase-32Fase 32 · El inglés deja de ser solo la marca · Cierre del plan bilingüe: /status, /demo, /log, /paginas-web, OG en inglés y contenido de BD
  • /status, /demo, /log y /paginas-web traducidas y dadas de alta en TRANSLATED_ROUTES.
  • Tiempos relativos y fechas por locale, sin cadenas en español coladas en la versión inglesa.
  • El formulario de contacto envía el locale y la notificación lo refleja.
  • tests/i18n-dictionary.test.ts y tests/i18n-routing.test.ts cubren las claves y rutas nuevas.
PF-I18-06historia
Aceptada

Como visitante anglófono, quiero que los proyectos del portafolio no vuelvan al español a mitad de página

#i18n#crm#fase-32Fase 32 · El inglés deja de ser solo la marca · Cierre del plan bilingüe: /status, /demo, /log, /paginas-web, OG en inglés y contenido de BD
  • Campos opcionales de título y descripción en inglés en el contenido de la base.
  • Helper de localización que cae al español cuando falta la traducción, en vez de dejar el hueco.
  • ProjectCard y la página de proyecto localizan título, descripción, estado y avance.
  • Variantes inglesas de las imágenes Open Graph.

Como responsable de la documentación (1)

PF-UML-02historia
Aceptada

Como responsable de la documentación, quiero que un diagrama mal formado falle en CI y no en la sustentación

#documentación#uml#testing#fase-33Fase 33 · Las notaciones que Mermaid no dibuja, y el entorno como código · Diagramas UML de despliegue, comunicación, actividades y componentes con motor propio; devcontainer y libSQL en contenedor
  • 54 tests de geometría y notación en tests/uml-{activity,communication,deployment,component}.test.ts.
  • Geometría: nada encimado, ninguna transición atravesando una figura ajena, todo elemento dentro de su nodo o partición.
  • Notación: decisiones con al menos dos salidas y todas con guarda, uniones con una sola salida, ningún final con transiciones salientes, ningún nodo inalcanzable.
  • /docs/diagrama-componentes rehecho como diagrama de componentes real; un test falla si vuelve a nombrar infraestructura.

Como presentador (1)

PF-PR-01historia
Aceptada

Como presentador, quiero proyectar desde cualquier pantalla y controlarla desde mi celular

#presentaciones#redis#tiempo-real#fase-34Fase 34 · Proyectar sin gastar servidor · Presentaciones con PIN en la raíz, control remoto desde el celular y público en sincronía
  • Tres vistas sobre una sesión: /present/[sessionId] proyecta, /remote/[sessionId] controla y /[pin] sigue en sincronía.
  • El control remoto no carga el iframe del deck: las notas salen de deck_slides, extraídas al subir el archivo.
  • Layout de dos mitades sin scroll, botones de 72 px, Wake Lock y vibración corta, todo con degradación silenciosa.
  • El deck se sirve desde /decks/[id].html (mismo origen) porque el control por DOM del iframe no funciona contra una URL de blob.

Como público (1)

PF-PR-02historia
Aceptada

Como público, quiero seguir la presentación en mi dispositivo escaneando un QR

#presentaciones#público#fase-34Fase 34 · Proyectar sin gastar servidor · Presentaciones con PIN en la raíz, control remoto desde el celular y público en sincronía
  • PIN de cuatro caracteres, dos letras y dos dígitos, sin i/l/o ni 0/1: 203.136 combinaciones y forma inconfundible con una ruta del sitio.
  • /[pin] es la última ruta en resolver; lo que no tiene forma de PIN devuelve el 404 normal sin llegar a consultar Redis.
  • Generación con reintento contra rutas reservadas y PIN vivos; un test cruza la lista de reservadas contra los archivos de src/pages.
  • Vista de solo lectura: sin controles, sin notas y con el teclado del deck neutralizado dentro del iframe.

Como responsable del coste (3)

PF-PR-03historia
Aceptada

Como responsable del coste, quiero tiempo real sin una invocación abierta por espectador

#presentaciones#arquitectura#coste#fase-34Fase 34 · Proyectar sin gastar servidor · Presentaciones con PIN en la raíz, control remoto desde el celular y público en sincronía
  • El público se suscribe DIRECTAMENTE al bus de Upstash con un token de solo lectura; Vercel solo trabaja al crear la sesión, al dar el snapshot y en cada comando.
  • Dos bases separadas: estado (privada, con el secreto del presentador) y bus (token público, solo números de slide).
  • Tres capas de sincronía: bus, resincronización cada 10 s y polling de rescate - pub/sub no garantiza entrega.
  • El servidor es la fuente de verdad: valida rango, persiste y reemite; el cliente descarta mensajes con versión anterior.
  • tests/present-sync.test.ts levanta dos clientes y comprueba que el salto llega a ambos, en orden, y que sin secreto no se mueve nada.
PF-CR-01historia
Aceptada

Como responsable del coste, quiero que una página pública lea lo mismo el primer día que el año siguiente

#coste#observabilidad#rendimiento#fase-37Fase 37 · Coste acotado, degradación elegante y respaldo verificable · Lo que se rompió cuando el sitio dejó de ser gratis de leer
  • Tabla monitor_daily con un resumen precalculado por monitor y día, alimentada por un cron nuevo (/api/cron/monitor-rollup); /status lee ~720 filas de resumen más el día en curso en vez de agregar los 90 días crudos de monitor_checks.
  • Medido contra la sqld local: 5.912 filas recorridas por render antes, 552 después.
  • Los contadores del resumen son exactos y aditivos; la latencia no, porque un percentil no se suma, así que cada día guarda un histograma de 32 cubos del que sale el p95 de la ventana, dentro del 7,4% del exacto que devolvía la window function.
  • La escalera de cubos es geométrica y no lineal: en un percentil importa el error relativo, y la primera versión lineal pintaba 2450 ms un p95 real de 2030.
  • tests/monitor-rollup.test.ts cubre histograma, percentil y agregación por día UTC.
PF-CR-02historia
Aceptada

Como responsable del coste, quiero que una prueba de carga no pueda alcanzar la base real

#k6#lab#coste#fase-37Fase 37 · Coste acotado, degradación elegante y respaldo verificable · Lo que se rompió cuando el sitio dejó de ser gratis de leer
  • El health check declara contra qué base está sirviendo el objetivo, y los perfiles de k6 (carga y estrés) se niegan a arrancar un solo usuario virtual si esa base no es local.
  • La guarda vive en el arranque de la prueba, no en la documentación: apuntar a localhost no basta cuando el dev server detrás puede estar conectado a Turso.
  • tests/db-target.test.ts cubre la detección de base local.

Como aprendiz (4)

PF-AP-01historia
Aceptada

Como aprendiz, quiero registrar cada sesión de práctica y ver si el hábito se sostiene

#aprendizaje#panel#fase-35Fase 35 · Medir el aprendizaje, no declararlo · Tracker de especialización técnica: racha, meta semanal, temario y logros derivados
  • Registro de sesión con día, minutos, tema, bitácora y hito relacionado; tres tablas nuevas (skill_tracks, skill_sessions, skill_milestones) en migración aditiva.
  • Racha con día de gracia: si la última sesión fue ayer sigue viva y se marca "en juego", en vez de romperse a las 00:00 de un día que apenas empieza.
  • Meta semanal configurable con lo que falta y el ritmo por día necesario para llegar antes del domingo.
  • Mapa de calor de 26 semanas con intensidad relativa al mejor día de la ventana, no a umbrales fijos.
PF-AP-02historia
Aceptada

Como aprendiz, quiero un temario concreto en vez de una intención vaga de "aprender .NET"

#aprendizaje#contenido#fase-35Fase 35 · Medir el aprendizaje, no declararlo · Tracker de especialización técnica: racha, meta semanal, temario y logros derivados
  • Temario semilla de 28 hitos en 8 áreas, de fundamentos de C# a desplegar una API real, con dos hitos de proyecto insignia.
  • La siembra es idempotente por título: volver a dispararla añade los hitos nuevos de la plantilla sin duplicar ni pisar el estado de los cerrados.
  • Los hitos se editan desde el panel una vez sembrados; la plantilla en src/data/track-dotnet.ts no vuelve a tocar un track existente.
PF-SP-01historia
Aceptada

Como aprendiz, quiero calcular las fechas de mi etapa productiva a partir de cuándo empiezo

#sena#personal#fase-41Fase 41 · Una calculadora personal para la propia etapa productiva · Hitos de la etapa productiva SENA y recordatorio por correo
  • src/lib/sena-ep.ts (módulo puro e isomorfo, sin node:crypto ni ../db) calcula computeHitos(tipo, inicioIso): inicio, visita de concertación a los 15 días, una bitácora por mes durante los 6 meses que dura la etapa productiva en los dos niveles (864 horas de diseño curricular, igual para técnico y tecnólogo), visita parcial de seguimiento y cierre 5 días después del fin nominal.
  • La calculadora en /ep exporta los hitos a .ics para importarlos al calendario del aprendiz y genera un enlace compartible con los parámetros en la URL. Cada evento lleva VALARM a 7 y 1 día: el recordatorio lo dispara el calendario del propio aprendiz, sin pedirle el correo ni guardar nada de un visitante.
  • src/lib/festivos-co.ts (módulo puro) calcula los 18 festivos colombianos del año - fijos, los que la Ley 51 de 1983 corre al lunes, y los móviles respecto al Domingo de Pascua por el algoritmo gregoriano anónimo - y marca los hitos que caen en fin de semana o festivo proponiendo el último día hábil. Cubierto por tests/festivos-co.test.ts contra fechas conocidas de Pascua y traslados Emiliani.
  • La página tiene hoja de impresión propia (@media print, is:global porque alcanza navbar y footer): oculta cromo, barra lateral y formularios, fuerza la paleta a tinta sobre papel y deja los checkbox de entrega vacíos para marcar a mano. El botón Imprimir / PDF existía desde antes sin estilos de impresión.
  • Un botón "Crear mi cronograma" lleva al formulario y deja el foco en la fecha. La ficha de la página sigue siendo la de referencia: el cronograma de otro aprendiz se calcula, no reemplaza el contenido por defecto.
  • 'ep' añadido a RESERVED_ROOT_SEGMENTS: Astro ya resuelve las estáticas antes que [pin].astro, así que el riesgo real es el inverso, que un PIN generado coincida con esta ruta y el público que escanee el QR aterrice en la página de etapa productiva en vez de en el deck. tests/present-reserved.test.ts falla si alguien añade una ruta raíz sin registrarla.
PF-SP-02historia
Aceptada

Como aprendiz, quiero un correo cuando se acerca un hito sin tener que volver a la página

#sena#cron#notificaciones#fase-41Fase 41 · Una calculadora personal para la propia etapa productiva · Hitos de la etapa productiva SENA y recordatorio por correo
  • src/pages/api/admin/sena-recordatorio.ts (bajo sesión admin: uso personal, nunca recolecta el email de nadie más) crea, consulta o cancela la única suscripción activa (tipo, inicio, diasAntes).
  • src/pages/api/cron/sena-recordatorio.ts recalcula hitos con computeHitos, filtra los que caen dentro de la ventana con hitosPorAvisar, y envía un único correo con sendEmail (notify.ts) al ALERT_EMAIL_TO ya configurado, nunca a un correo del request.
  • notifiedKeys evita reavisar el mismo hito: cada clave es título+fecha, persistida tras un envío exitoso.
  • Fail-open como el resto de los crons de observabilidad: un fallo se registra en logs y responde 200 en vez de tumbar el cron.

Como responsable de que el dato sea correcto (1)

PF-AP-03historia
Aceptada

Como responsable de que el dato sea correcto, quiero que la racha no dependa de la zona horaria del servidor

#aprendizaje#correctitud#testing#fase-35Fase 35 · Medir el aprendizaje, no declararlo · Tracker de especialización técnica: racha, meta semanal, temario y logros derivados
  • Los días se guardan como clave de calendario "YYYY-MM-DD" en zona de Bogotá, no como timestamp: el servidor corre en UTC y una sesión de las 8 de la noche caería en el día siguiente, partiendo la racha.
  • Los logros se derivan de las sesiones en cada render en vez de persistirse: una tabla de badges se desincroniza al borrar una sesión mal registrada.
  • Cada logro queda fechado en el día en que se cumplió (cruce del umbral acumulado, cierre de la racha), no en el día en que se consulta el panel.
  • tests/skills.test.ts: 31 casos sobre el módulo puro, incluidos cambio de mes, año bisiesto, fin de año, corte de racha a los dos días y niveles relativos del mapa de calor.

Como dueño del sitio (1)

PF-AP-04historia
Aceptada

Como dueño del sitio, quiero poder mostrar el avance sin publicar mi bitácora

#aprendizaje#opsec#i18n#fase-35Fase 35 · Medir el aprendizaje, no declararlo · Tracker de especialización técnica: racha, meta semanal, temario y logros derivados
  • Visibilidad por track (is_public, privado por defecto); /certifications publica solo el agregado: horas, porcentaje del temario y mejor racha.
  • La bitácora, las fechas de cada sesión y los hitos individuales no salen del panel, misma regla de OPSEC que /status.
  • Un track recién sembrado y sin sesiones no aparece en público: cero horas y cero por ciento no dicen nada bueno.
  • Sección traducida en los dos diccionarios (es/en), que es lo que exige la paridad de claves de npx astro check.

Como capacitador (1)

PF-CP-01historia
Aceptada

Como capacitador, quiero que el material siga sirviendo cuando termina la sesión

#capacitacion#panel#publico#fase-36Fase 36 · Capacitación en IA como línea de negocio · Banco de recursos con acceso por código de grupo y landing de capacitación
  • Tres tablas nuevas en migración aditiva: training_programs (catálogo), training_resources (banco) y training_access_codes (grupos).
  • Banco público en /capacitacion con detalle por recurso; el contenido es markdown en base de datos, renderizado en el servidor con un subconjunto propio que escapa el HTML antes de formatear.
  • Las presentaciones no se duplican: un recurso de tipo deck referencia la tabla decks, que sigue siendo la única fuente de verdad del material proyectable.
  • La previsualización del panel usa el mismo renderizador que la página pública, para que no sea una previsualización que miente.

Como dueño de los datos (1)

PF-CR-04historia
Aceptada

Como dueño de los datos, quiero saber si el backup diario realmente se está haciendo

#backup#crons#fase-37Fase 37 · Coste acotado, degradación elegante y respaldo verificable · Lo que se rompió cuando el sitio dejó de ser gratis de leer
  • Descubierto con el store de Blob vacío: un mes sin un solo archivo. Dos fallos que se tapaban entre sí: el endpoint vivía bajo /api/admin/, donde el middleware exige sesión y el cron se llevaba un 302; y el handler del backup era POST mientras que los crons de Vercel disparan GET, con lo que la petición diaria caía en el GET de "listar backups" y devolvía 200.
  • El backup se mueve a /api/cron/backup con Bearer CRON_SECRET, y es el único cron del repo que NO es fail-open: devuelve 500 cuando falla, porque un cron que solo puede responder 200 no está verificado, está silenciado.
  • tests/crons.test.ts recorre cada entrada de vercel.json y afirma las cuatro condiciones que fallaban: la ruta existe, exporta GET, comprueba CRON_SECRET y no cuelga del gate de /api/admin. Ninguna necesita desplegar para comprobarse.
  • La ruta del cron queda vetada en la demo, cubierto por tests/demo.test.ts.

Como responsable del incidente (1)

PF-RT-01tarea
Aceptada

Como responsable del incidente, quiero un procedimiento escrito para la próxima vez que la cuota se agote

#runbook#coste#fase-38Fase 38 · El incidente de cuota no se cierra arreglando el código, se cierra con un runbook · Datos sintéticos verificables y el camino de recuperación completo
  • docs/runbook-cuota-turso.md documenta qué pasó (86.000 filas leídas por llamada a /api/now.ts pese a devolver un único número), la regla que lo evita (ningún agregado público sobre ventanas >24h sin rollup) y que es la tercera vez que el mismo patrón agota la cuota.
  • Dos caminos de recuperación documentados: aguantar hasta el corte del ciclo (la capa de respaldo de RNF-27 se apaga sola) o mudar a una base nueva, con el requisito de que ENCRYPTION_KEY debe coincidir para no perder la bóveda.
  • /api/now.ts (error budget) y /api/engineering/live.ts pasan a leer de monitor_daily en vez de agregar monitor_checks/web_vitals crudos; este último además cambia no-store por s-maxage=30.

Como quien prueba el modo respaldo (1)

PF-RT-02tarea
Aceptada

Como quien prueba el modo respaldo, quiero historial de monitoreo sin esperar un incidente real

#datos-sinteticos#testing#fase-38Fase 38 · El incidente de cuota no se cierra arreglando el código, se cierra con un runbook · Datos sintéticos verificables y el camino de recuperación completo
  • scripts/seed-monitor-history.mjs genera sondeos en memoria y los pasa por aggregateChecks, el mismo módulo real de rollup que usa el cron en producción: el histograma queda con los mismos cubos.
  • 90 días de monitor_daily (~900 filas) pero solo 2 días de monitor_checks (~5.700): sembrar 90 días de crudo para alimentar los 40 puntos de la mini-gráfica EKG habría repetido el mismo error de volumen que causó el incidente.
  • El azar es determinista (derivado de monitor+instante): dos corridas producen el mismo p95, y el perfil de latencia no se realimenta de monitors.last_response_ms para no derivar entre pasadas.
  • scripts/restore-backup.mjs repuebla las tablas de negocio desde el último backup de Blob con --dry-run obligatorio antes de escribir, y se niega a pisar tablas con filas salvo --forzar.

Como visitante en modo respaldo (1)

PF-RT-03tarea
Aceptada

Como visitante en modo respaldo, quiero que /status y el poll no sigan trabajando cuando no los veo

#rendimiento#fase-38Fase 38 · El incidente de cuota no se cierra arreglando el código, se cierra con un runbook · Datos sintéticos verificables y el camino de recuperación completo
  • El poll de /status (30s) y el de /docs/pipeline-en-vivo (6s → 15s) se detienen con la pestaña oculta (Page Visibility API).
  • DESTINOS_RESPALDO deja deliberadamente FUERA los tres servicios pausados a mano en Vercel (DEPLOYMENT_PAUSED) mientras dura el ahorro de cuota: sondearlos los pintaría "Caído" durante semanas por una decisión operativa, no por una avería, y un panel de estado que reporta como incidente algo que su dueño apagó a propósito enseña a ignorarlo.

Como quien entrega evidencia (1)

PF-EP-02historia
Aceptada

Como quien entrega evidencia, quiero explicar qué log produce cada reporter antes de citarlo

#testing#documentacion#fase-39Fase 39 · La evidencia de testing deja de vivir solo en la terminal · Instantánea de la corrida real, referencia de reporters y hallazgos de k6 publicados
  • /docs/reportes-pruebas documenta los 7 reporters de Vitest (default, verbose, dot, tap-flat, junit, json, html) con salida real capturada de tests/phone.test.ts, no reescrita, incluida la anatomía de un fallo provocado a propósito.
  • Tabla de equivalencias con el instrumental de Java (Surefire, JaCoCo, PIT), porque el vocabulario estándar de pruebas viene de Maven y los nombres coinciden solo a medias.
  • Documentado con el error literal que devuelve el reporter html si falta la dependencia @vitest/ui.

Como responsable del LAB (1)

PF-EP-03tarea
Aceptada

Como responsable del LAB, quiero los hallazgos de las corridas de k6 reflejados donde se sustenta

#k6#lab#fase-39Fase 39 · La evidencia de testing deja de vivir solo en la terminal · Instantánea de la corrida real, referencia de reporters y hallazgos de k6 publicados
  • RF-505 actualizado con los hallazgos H-01 a H-05 de la corrida de referencia: el colapso es de concurrencia, no hay margen amplio entre nivel sano y roto, y sin ventana de enfriamiento la recuperación puede no completarse en 120s.
  • lab/k6/estres.js deja de falsear "CPU 0%" cuando el propio endpoint de muestreo (proceso.ts) se satura bajo la prueba; ahora distingue explícitamente "sin dato".
  • Prerendering habilitado en páginas estáticas de /docs para alinear el comportamiento de build con la realidad de producción.

Como autor del modelo (1)

PF-DR-02historia
Aceptada

Como autor del modelo, quiero que un flujo no pueda saltarse un perímetro sin que el test lo note

#testing#geometria#fase-40Fase 40 · La pregunta que el diagrama de despliegue no responde · Diagrama de red por zonas de confianza
  • tests/red.test.ts verifica geometría (zonas sin solaparse, host dentro de su zona, ninguna traza atravesando una zona ajena a sus extremos, rótulos sin encimarse) y notación (todo flujo con protocolo, todo cruce con puerto y al menos un control, ningún host aislado).
  • Regla dura verificada con tres pruebas hostiles a propósito: un flujo que se salta el perímetro, un cruce sin control y un host huérfano, exigiendo que el verificador los detecte.
  • findLayoutIssues corregido para usar bboxZona (la caja real, incluida la cabecera de la zona) tras encontrar cabeceras encimadas que la primera versión no detectaba.