Saltar a contenido

ADR-025 — Acta con premio original congelado + separación del estado de entrega; plazo visible; paginación de clientes

  • Status: accepted (2026-08-23; reabierto por judgment-day — CRIT-2, #6, #7)
  • Context (CRIT-2): El acta garantiza reproducibilidad del sorteo (seed+lista+algo → mismos ganadores), pero su export incluye premio_unidad_id y estado_entrega, que MUTAN con la operación (entrega, devolución, pase a suplente). Dos exports del mismo acta muestran premios/estados distintos, confundiendo el artefacto legal (lo sorteado) con el estado operativo (lo entregado). El sorteo en sí es inmutable; la entrega evoluciona.
  • Decision (CRIT-2):
  • resultado_sorteo gana premio_unidad_id_original (BIGINT nullable), seteado UNA VEZ al ejecutar (SorteoService.persistirResultados) y NUNCA modificado por las operaciones de entrega. Migración V10: agrega la columna y la backfillea con el premio_unidad_id actual para actas ya existentes.
  • El export del acta se parte en dos secciones EXPLÍCITAS:
    1. Acta del sorteo (INMUTABLE) — fecha_ejecucion, seed, algo_version, hash_lista, cantidad_participantes, y por cada posición: orden, tipo, chance/cliente, y el premio sorteado originalmente (premio_unidad_id_original). Reproducible: matchea hash_lista y reproducir().
    2. Estado de entrega (snapshot, con exportado_en) — por cada resultado: premio actual, estado_entrega, datos de entrega. Claramente rotulado como estado al momento del export.
  • Dos exports en momentos distintos: la sección 1 es idéntica; la 2 puede diferir.
  • Decision (#6 — plazo de retiro): NO se automatiza (un scheduler violaría ADR-009 y podría despojar a un ganador legítimo). Se VISIBILIZA: la vista de ganadores expone plazo_vencido (días desde el primer contacto vs campania.plazo_retiro_dias); registrarEntrega sobre un resultado con plazo vencido exige un flag de confirmación explícito (no bloquea, advierte).
  • Decision (#7 — clientes): la búsqueda del padrón exige un término mínimo (query vacío no materializa todo el padrón) y se pagina server-side (Pageable, tope por página). Evita cargar decenas de miles de filas al abrir la pantalla en una campaña con volumen.
  • Consequences: El acta protege su valor legal (lo sorteado nunca cambia) sin perder la trazabilidad operativa (estado de entrega como snapshot). El plazo queda como decisión informada del operador. La pantalla de clientes escala con el padrón.

Verification

  • [x] AC-44 — premio_unidad_id_original congelado al ejecutar; el export separa "acta (inmutable)" de "estado de entrega (snapshot)". Tras una devolución, dos exports: la sección de acta es idéntica (hash estable, reproduce() matchea), la de entrega difiere.
  • [x] AC-45 — Ganadores expone plazo_vencido (días desde primer contacto vs plazo); registrarEntrega con plazo vencido sin confirmación → advertencia/409; con confirmación explícita → procede. Nunca auto-transiciona a NO_OTORGADO.
  • [x] AC-46 — Búsqueda de clientes: query vacío no carga el padrón completo (400/paginado); respuesta paginada (page/size/total). Test con volumen confirma que no materializa todo.