Quickstart — Validación de la 006 (guía de ejecución, sin código de implementación)

Prerrequisitos: repo en 006-tiempo-referencia, Node 22, dependencias instaladas. Reloj controlado: los escenarios fijan ahora explícito (inyectado a lib/ventanas.ts), nunca el reloj real. Referencias: fórmulas en data-model.md, firmas en contracts/ventanas-tiempo.md.

QS-1 — Un único «ahora» por operación (US1, FR-001, SC-001)

  1. Fijar ahora = 30/09/2026, 10:00 (Europe/Madrid).
  2. Ejecutar en una misma operación: validación de alta + cancelacionEnPlazo + enVentanaRecordatorios.
  3. Avanzar el reloj real 2 minutos a mitad de operación y repetir las tres validaciones.
  4. Esperado: las tres usan 30/09/2026, 10:00 en ambos intentos; cero discrepancias pasado/futuro entre features.

QS-2 — RN2 pasado al minuto (FR-004, SC-002)

  1. Con ahora = 30/09/2026, 10:00: esPasado(30/09/2026 09:59) y esPasado(30/09/2026 10:00).
  2. Esperado: 09:59 ⇒ true (pasado en alta, portal y recordatorios); 10:00 ⇒ false (el borde es estricto: solo lo anterior es pasado).

QS-3 — Antelación de cancelación 24 h (FR-005, SC-002)

  1. Con ahora fijado: cancelacionEnPlazo(ahora + 24 h 00 min) y cancelacionEnPlazo(ahora + 23 h 59 min).
  2. Esperado: 24 h 00 min ⇒ true (borde incluido); 23 h 59 min ⇒ false. Sin tope superior (+30 días ⇒ true).

QS-4 — Ventana de recordatorios 24–48 h (FR-006, SC-002)

  1. Fijar ejecucion = 01/10/2026, 00:00; evaluar citas a +24 h y +48 h exactas, más una a +23 h 59 min y otra a +48 h 01 min.
  2. Esperado: 24 h ⇒ true, 48 h ⇒ true (bordes incluidos); 23:59 ⇒ false, 48:01 ⇒ false.

QS-5 — 8 semanas cerradas, curso fuera (FR-007/FR-009, SC-002)

  1. Abrir un miércoles (p. ej. 30/09/2026) y llamar semanasAnalitica(hoy).
  2. Esperado: 8 filas S-8…S-1, semanas naturales cerradas lunes–domingo anteriores; la semana del 30/09 queda fuera; cada fila etiquetada S-N: DD/MM/AAAA–DD/MM/AAAA derivada de la ventana, sin constantes.

QS-6 — Denominador honesto (FR-008, SC-003)

  1. Con defecto (09:00–20:00, Lun–Vie): denominadorOcupacion("09:00","20:00").
  2. Reconfigurar a Lun–Sáb y repetir.
  3. Esperado: (1) { minutos: 26400, etiquetaJornada: "09:00–20:00, Lun–Vie" }; (2) { minutos: 31680, …Sáb }, distinto de 26.400; la jornada/días aparecen junto a cada porcentaje (FR-009).

QS-7 — Cero duplicados (FR-010, SC-004)

  1. Ejecutar grep -rn "now()\|CURRENT_TIMESTAMP\|Europe/\|España (península)\|24 *h\|48 *h\|S-[18]" --include="*.ts" lib app prisma | grep -v "lib/\(tiempo\|ventanas\).ts" (canónica D7/T021; diasLaborables no se grepa: es campo legítimo).
  2. Revisar que fuera de lib/tiempo.ts, lib/ventanas.ts y citas 006 FR-00X no haya definiciones rivales de «ahora», zona, precisión, bordes ni ventanas (cada hit se revisa a mano).
  3. Esperado: cero definiciones duplicadas; cualquier hallazgo es defecto (FR-010). Incluir este grep en cada merge.

Comandos de test (tras /speckit.tasks + implementación): npm run test -- test_ventanas_tiempo y npm run typecheck. Sin Playwright en esta feature (sin UI nueva).