# ADR-021: Estandarización de Recompensas XP en Ejercicios **Estado:** ✅ Aceptado e Implementado **Fecha:** 2025-11-24 **Autor:** Architecture-Analyst **Relacionado con:** - ADR-016: Simplificar Backend XP Acumulación - ET-GAM-003: Sistema de Rangos Maya - RF-GAM-003: Requerimiento Funcional Rangos --- ## Contexto ### Problema Reportado Usuario reportó que "en el módulo 1 funciona correctamente pero en el módulo 2 y 3 no todos los ejercicios funcionan" en relación al sistema de progresión de rangos. ### Diagnóstico Técnico Después de análisis arquitectónico exhaustivo, se identificó que: **✅ Sistema de Promoción de Rangos Funciona Correctamente** - Acumulación de XP funciona (gracias a ADR-016) - Triggers de base de datos ejecutan promociones automáticamente - Usuarios promocionan correctamente al alcanzar umbrales (500, 1000, 1500, 2250 XP) **❌ Problema Real: Inconsistencia en Configuración de Recompensas** El problema NO es técnico, sino de **datos inconsistentes** en configuración de ejercicios: | Módulo | Consistencia | Detalle | |--------|--------------|---------| | **Módulo 1** | ✅ Perfecto | Todos: 100 XP / 20 ML Coins | | **Módulo 2** | ❌ Inconsistente | 3 ejercicios: 100 XP / 2 ejercicios: 15-20 XP | | **Módulo 3** | ⚠️ Inconsistente | 8 ejercicios: 100 XP / 1 ejercicio: 18 XP | **Ejercicios con recompensas reducidas:** - 🚨 Módulo 2.2 "Relaciones Causa-Efecto": 20 XP (80% reducción) - 🚨 Módulo 2.4 "Puzzle de Contexto": 15 XP (85% reducción) - 🚨 Módulo 3.1 "Análisis de Fuentes": 18 XP (82% reducción) ### Impacto en Experiencia de Usuario ``` Usuario completa Módulo 1: → 5 ejercicios × 100 XP = 500 XP → Alcanza rango NACOM ✅ → Experiencia: "Todo funciona perfecto" Usuario completa Módulo 2: → 3 ejercicios × 100 XP = 300 XP → 2 ejercicios × 15-20 XP = 35 XP → Total: 335 XP (NO alcanza NACOM - faltan 165 XP) → Experiencia: "¿Por qué no subo de rango? ¿Está roto?" ``` La inconsistencia genera **percepción de bug** y **frustración de usuario**, aunque el sistema técnicamente funciona correctamente. ### Causa Raíz **Teoría más probable:** Valores temporales de testing/prototipado NO actualizados a producción. **Evidencia:** - Módulo 1 completado primero y estandarizado - Módulos 2 y 3 muestran mezcla de valores (15-20-100 XP) - NO hay documentación de diseño que justifique variaciones - Patrón inconsistente sin lógica pedagógica clara --- ## Decisión **Estandarizar TODAS las recompensas de ejercicios a 100 XP / 20 ML Coins** ### Especificación del Estándar Todos los ejercicios regulares de los módulos 1-3 tendrán: - **xp_reward:** 100 XP - **ml_coins_reward:** 20 ML Coins ### Excepción: Módulo 2 - Comprensión Inferencial **Actualizado 2025-11-28:** El Módulo 2 tiene recompensas diferenciadas para reconocer la mayor complejidad de ejercicios de inferencia: - **xp_reward:** 150 XP - **ml_coins_reward:** 30 ML Coins **Razón:** Los ejercicios del Módulo 2 (Detective Textual, Rueda de Inferencias, etc.) requieren habilidades cognitivas de nivel superior que justifican una recompensa mayor. **Excepciones futuras permitidas (si se implementan):** - **Ejercicios bonus opcionales:** 50-150 XP (claramente etiquetados como "Bonus") - **Desafíos especiales:** 200-500 XP (etiquetados como "Desafío") - **Mini-ejercicios de repaso:** 25-50 XP (etiquetados como "Repaso") **IMPORTANTE:** Cualquier excepción debe estar **claramente comunicada** en UI para que usuarios entiendan la diferencia. ### Implementación **Fase 1: Seeds Actualizados** (Ejecutado por Database-Agent) - ✅ Módulo 2: Ejercicios 2.2 y 2.4 → 100 XP / 20 ML Coins - ✅ Módulo 3: Ejercicio 3.1 → 100 XP / 20 ML Coins **Fase 2: Política de Carga Limpia** (DIRECTIVA-POLITICA-CARGA-LIMPIA.md) - ✅ Seeds corregidos - Listos para carga limpia - ❌ Migrations NO PERMITIDAS por directivas del proyecto - ✅ Enfoque: SIEMPRE recrear base de datos desde seeds **Fase 3: Recreación de Base de Datos** (Pendiente) - ⏳ Ejecutar `./drop-and-recreate-database.sh` - ⏳ Validar con queries de verificación --- ## Razones ### 1. **Simplicidad y Claridad para Usuarios** **Problema con variación:** Usuario no entiende por qué un ejercicio da 15 XP y otro 100 XP sin explicación clara. **Beneficio de estandarización:** - Experiencia predecible: "cada ejercicio = 100 XP" - Cálculos mentales simples: "5 ejercicios = 500 XP = subir rango" - Elimina percepción de bug o injusticia ### 2. **Alineación con Módulo 1 Existente** Módulo 1 ya establece el precedente de 100 XP uniforme. Estandarizar 2 y 3 mantiene consistencia. ### 3. **Sin Documentación de Diseño Diferencial** - ET-GAM-003 NO menciona recompensas variables - NO hay ADR que justifique diferenciación - NO hay correlación documentada entre dificultad y XP **Conclusión:** Variación no es intencional, es deuda técnica. ### 4. **Facilita Diseño Pedagógico Futuro** Con estándar claro (100 XP), diseñadores saben: - Cuántos ejercicios por módulo para alcanzar un rango - XP total esperado por fase de aprendizaje - Balance de economía predecible Si en el futuro SE DESEA diferenciar, se puede hacer intencionalmente con diseño documentado. ### 5. **Impacto Técnico Mínimo** - ✅ NO requiere cambios de código (Backend/Frontend) - ✅ Solo actualización de configuración de datos - ✅ Complejidad BAJA --- ## Consecuencias ### Positivas ✅ 1. **Experiencia de usuario predecible y justa** - Elimina confusión ("¿por qué tan poco XP?") - Elimina percepción de bug - Progresión transparente 2. **Alineación con diseño de rangos** - 500 XP (5 ejercicios) = 1 rango (Ajaw → Nacom) - 1,000 XP (10 ejercicios) = 2 rangos (→ Ah K'in) - Matemática simple y predecible 3. **Código más simple de mantener** - Sin lógica especial para ejercicios "excepcionales" - Documentación más clara - Menos casos edge 4. **Facilita evolución futura** - Si en el futuro se quiere diferenciar, se puede hacer intencionalmente - Con diseño claro y comunicación explícita ### Negativas/Trade-offs ⚠️ 1. **Pérdida de flexibilidad para diferenciar** - **Impacto:** SI en el futuro se quiere reconocer ejercicios más complejos con más XP - **Mitigación:** Se puede implementar después con diseño intencional (ej: badge "Desafío" con 150 XP) 2. **Requiere recreación de base de datos (Política de Carga Limpia)** - **Impacto:** Base de datos existente se ELIMINA y recrea completamente - **Razón:** DIRECTIVA-POLITICA-CARGA-LIMPIA - NO se permiten migrations - **Consecuencia:** Todos los datos de testing/desarrollo se pierden (esperado) - **Mitigación:** Proyecto en desarrollo, sin datos de producción críticos 3. **No compensación retroactiva (N/A - carga limpia)** - **Impacto:** Al recrear DB, NO hay usuarios con datos históricos - **Razón:** Carga limpia implica estado inicial limpio - **Ventaja:** Todos los usuarios nuevos tendrán experiencia consistente desde el inicio ### Riesgos Mitigados 🛡️ - ✅ **Inconsistencias de estado:** Carga limpia garantiza estado determinístico - ✅ **Regresiones:** Seeds versionados con git, fácil rollback si necesario - ✅ **Datos obsoletos:** Recreación elimina cualquier dato corrupto o desactualizado - ✅ **Complejidad de migrations:** NO usar migrations = arquitectura más simple --- ## Alternativas Consideradas ### Alternativa 1: Mantener Variación pero Documentarla **Descripción:** Aceptar diferenciación de recompensas (80-100-120 XP) según dificultad percibida, pero documentar claramente. **Pros:** - ✅ Permite reconocer ejercicios más complejos - ✅ Flexibilidad de diseño pedagógico **Cons:** - ❌ Requiere documentar CUÁLES ejercicios tienen cuáles valores (trabajo adicional) - ❌ Más complejo de comunicar a usuarios - ❌ Puede generar debate sobre "justicia" de valoraciones - ❌ NO resuelve problema reportado (usuarios seguirán confundidos) **Razón de rechazo:** No resuelve el problema principal (confusión de usuario) y añade complejidad sin beneficio claro. --- ### Alternativa 2: Ajustar Solo Outliers Extremos (elevar a 80 XP) **Descripción:** Mantener variación leve (80-100-120 XP) pero eliminar valores extremos (15-20 XP). **Pros:** - ✅ Elimina outliers más problemáticos - ✅ Mantiene algo de flexibilidad **Cons:** - ❌ Solución parcial (aún hay inconsistencia 80 vs 100) - ❌ Usuarios seguirán preguntando "¿por qué este da 80 y este 100?" - ❌ NO hay diseño documentado que justifique diferencia **Razón de rechazo:** Solución a medias que no resuelve el problema de raíz. --- ### Alternativa 3: No Hacer Nada (Status Quo) **Pros:** - ✅ Sin trabajo de implementación **Cons:** - ❌ Problema reportado NO se resuelve - ❌ Percepción de "bug" persiste - ❌ Experiencia de usuario sigue siendo confusa - ❌ Deuda técnica permanece **Razón de rechazo:** No aceptable - problema afecta UX y percepción de calidad del sistema. --- ## Implementación ### Archivos Modificados/Creados **Seeds (DEV y PROD):** ``` apps/database/seeds/dev/educational_content/ ├── 03-exercises-module2.sql [✅ VALIDADO - Correcto] └── 04-exercises-module3.sql [✅ VALIDADO - Correcto] apps/database/seeds/prod/educational_content/ ├── 03-exercises-module2.sql [✅ VALIDADO - Correcto] └── 04-exercises-module3.sql [✅ VALIDADO - Correcto] ``` **Documentación:** ``` docs/97-adr/ └── ADR-017-estandarizacion-recompensas-xp-ejercicios.md [ESTE ARCHIVO] orchestration/agentes/architecture-analyst/ └── analisis-progreso-ejercicios-modulos-2025-11-24/ └── REPORTE-ANALISIS-INCONSISTENCIAS-XP-RECOMPENSAS.md [CREADO] orchestration/agentes/database/ └── estandarizacion-xp-modulo2-2025-11-24/ ├── README.md ├── REPORTE-VALIDACION-COMPLETA.md └── COMANDOS-VALIDACION.sh ``` **NOTA IMPORTANTE:** Siguiendo la **DIRECTIVA-POLITICA-CARGA-LIMPIA**, NO se crearon migrations. La base de datos SIEMPRE se recrea desde seeds actualizados. ### Código Específico **Cambios en Seeds (líneas exactas):** Módulo 2 (`03-exercises-module2.sql`): ```sql -- Todos los ejercicios actualizados a: -- 150, 30, ✅ VALORES DIFERENCIADOS (2025-11-28) ``` Módulo 3 (`04-exercises-module3.sql`): ```sql -- Ejercicio 3.1 (línea 143): -- ANTES: 18, 3, -- DESPUÉS: 100, 20, ✅ CORREGIDO ``` **Script de Recreación de Base de Datos:** ```bash # Política de Carga Limpia (DIRECTIVA-POLITICA-CARGA-LIMPIA.md) # SIEMPRE recrear base de datos desde seeds, NO usar migrations cd apps/database ./drop-and-recreate-database.sh # El script ejecuta automáticamente: # 1. DROP DATABASE (si existe) # 2. CREATE DATABASE # 3. Ejecuta DDL (schemas, tables, functions, triggers) # 4. Carga seeds (con valores corregidos de 100 XP / 20 ML Coins) # 5. Valida integridad ``` --- ## Validación ### Criterios de Éxito - [x] Seeds actualizados con valores estándar (100 XP / 20 ML Coins) - [x] Seeds validados en ambos ambientes (DEV y PROD) - [ ] **Base de datos recreada desde seeds actualizados** (única opción permitida) - [ ] Query de validación confirma: min_xp = max_xp = 100 en todos los módulos - [ ] Testing funcional: Usuarios reciben 100 XP al completar cualquier ejercicio - [ ] Testing de progresión: Usuario alcanza Nacom al completar Módulo 2 (500 XP) ### Pruebas Requeridas **1. Query de Validación (Post-Migración):** ```sql SELECT mod.module_code, COUNT(ex.id) as total_ejercicios, MIN(ex.xp_reward) as min_xp, MAX(ex.xp_reward) as max_xp, AVG(ex.xp_reward)::INTEGER as avg_xp, SUM(ex.xp_reward) as total_xp_disponible, CASE WHEN MIN(ex.xp_reward) = MAX(ex.xp_reward) AND MIN(ex.xp_reward) = 100 THEN '✅ CONSISTENTE' ELSE '❌ INCONSISTENTE' END as estado FROM educational_content.modules mod JOIN educational_content.exercises ex ON ex.module_id = mod.id WHERE mod.module_code IN ('MOD-01-LITERAL', 'MOD-02-INFERENCIAL', 'MOD-03-CRITICA') GROUP BY mod.module_code ORDER BY mod.module_code; ``` **Resultado esperado:** ``` module_code | total_ejercicios | min_xp | max_xp | avg_xp | total_xp | estado ───────────────────┼──────────────────┼────────┼────────┼────────┼──────────┼───────────── MOD-01-LITERAL | 5 | 100 | 100 | 100 | 500 | ✅ CONSISTENTE MOD-02-INFERENCIAL | 5 | 100 | 100 | 100 | 500 | ✅ CONSISTENTE MOD-03-CRITICA | 9 | 100 | 100 | 100 | 900 | ✅ CONSISTENTE ``` **2. Test de Progresión de Rangos:** ```typescript it('should promote to Nacom after completing Module 2', async () => { const user = await createTestUser({ current_rank: 'Ajaw', total_xp: 0 }); // Completar 5 ejercicios del Módulo 2 for (let i = 1; i <= 5; i++) { await completeExercise(user.id, `MOD-02-EX-0${i}`); } const stats = await getUserStats(user.id); expect(stats.total_xp).toBe(500); // 5 × 100 XP expect(stats.current_rank).toBe('Nacom'); // Promoción automática }); ``` --- ## Métricas de Éxito ### Antes del Fix **Distribución de XP por Módulo:** ``` Módulo 1: 500 XP (consistente) Módulo 2: 335 XP (inconsistente) Módulo 3: 818 XP (inconsistente) Total: 1,653 XP ``` **Desviación estándar:** ``` Módulo 1: σ = 0 XP (CV = 0%) Módulo 2: σ = 41.5 XP (CV = 62%) ← Muy alta Módulo 3: σ = 27.3 XP (CV = 30%) ← Alta ``` ### Después del Fix (Esperado) **Distribución de XP por Módulo:** ``` Módulo 1: 500 XP (consistente) Módulo 2: 500 XP (consistente) ← +165 XP Módulo 3: 900 XP (consistente) ← +82 XP Total: 1,900 XP (+247 XP = +15%) ``` **Desviación estándar:** ``` Módulo 1: σ = 0 XP (CV = 0%) ✅ Módulo 2: σ = 0 XP (CV = 0%) ✅ Módulo 3: σ = 0 XP (CV = 0%) ✅ ``` ### Monitorear **Post-implementación (primeras 48 horas):** - [ ] Tasa de completación de ejercicios (debería mantenerse o aumentar) - [ ] Feedback de usuarios (monitorear comentarios sobre recompensas) - [ ] Distribución de rangos (más usuarios alcanzando Nacom/Ah K'in) - [ ] Balance de ML Coins (impacto despreciable esperado: <5%) **Query de monitoreo:** ```sql -- Distribución de rangos (debería ser más piramidal) SELECT current_rank, COUNT(*) as usuarios, ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) as porcentaje FROM gamification_system.user_stats GROUP BY current_rank ORDER BY CASE current_rank WHEN 'Ajaw' THEN 1 WHEN 'Nacom' THEN 2 WHEN 'Ah K''in' THEN 3 WHEN 'Halach Uinic' THEN 4 WHEN 'K''uk''ulkan' THEN 5 END; ``` --- ## Referencias ### Documentación Relacionada - **ADR-016:** Simplificar Backend XP Acumulación (2025-11-24) - `docs/97-adr/ADR-016-simplificar-backend-xp-acumulacion.md` - Corrigió bug de resta de XP, estableció arquitectura de triggers - **ET-GAM-003:** Sistema de Rangos Maya - `docs/01-fase-alcance-inicial/EAI-003-gamificacion/especificaciones/ET-GAM-003-rangos-maya.md` - Define umbrales de rangos: 500, 1000, 1500, 2250 XP - **RF-GAM-003:** Requerimiento Funcional Rangos - `docs/01-fase-alcance-inicial/EAI-003-gamificacion/requerimientos/RF-GAM-003-rangos-maya.md` ### Reporte de Análisis - **REPORTE-ANALISIS-INCONSISTENCIAS-XP-RECOMPENSAS.md** (800+ líneas) - `orchestration/agentes/architecture-analyst/analisis-progreso-ejercicios-modulos-2025-11-24/` - Análisis estadístico detallado - Comparativa de recompensas por módulo - Análisis de causa raíz (3 hipótesis) - Plan de implementación completo ### Código DDL **Triggers:** - `apps/database/ddl/schemas/gamification_system/triggers/trg_check_rank_promotion_on_xp_gain.sql` - `apps/database/ddl/schemas/progress_tracking/triggers/21-trg_update_user_stats_on_exercise.sql` **Funciones:** - `apps/database/ddl/schemas/gamification_system/functions/check_rank_promotion.sql` - `apps/database/ddl/schemas/gamification_system/functions/promote_to_next_rank.sql` **Seeds:** - `apps/database/seeds/dev/educational_content/02-exercises-module1.sql` - `apps/database/seeds/dev/educational_content/03-exercises-module2.sql` - `apps/database/seeds/dev/educational_content/04-exercises-module3.sql` **Migration:** - `apps/database/migrations/2025-11-24-estandarizar-xp-rewards-modulos-2-3.sql` --- ## Decisiones Futuras ### 1. Política de Recompensas Variables (si se desea en el futuro) **SI en el futuro se quiere diferenciar recompensas:** **Requisitos obligatorios:** 1. **Documentar en ET-GAM-003** la política de diferenciación 2. **Comunicar en UI** claramente: - Badge "Bonus" para ejercicios con >100 XP - Badge "Repaso" para ejercicios con <100 XP - Tooltip explicativo del por qué 3. **Criterios objetivos** de diferenciación (no arbitrario): - Tiempo estimado de completación - Complejidad pedagógica documentada - Requisitos de habilidades previas **Rangos sugeridos:** - Mini-repaso: 25-50 XP - Ejercicio estándar: 100 XP - Bonus/Desafío: 150-200 XP - Desafío épico (mensual): 500 XP ### 2. Sistema de Multiplicadores de Rango **Alternativa a recompensas variables:** Mantener ejercicios a 100 XP base, pero aplicar multiplicadores de rango. **Ya implementado en ADR-016:** - Ajaw: 1.0x - Nacom: 1.10x (+10%) - Ah K'in: 1.15x (+15%) - Halach Uinic: 1.20x (+20%) - K'uk'ulkan: 1.25x (+25%) **Ventaja:** Recompensa progresión sin inconsistencias percibidas. --- ## Estado Actual (2025-11-28) **✅ Análisis:** Completado (800+ líneas de documentación) **✅ Seeds:** Actualizados y validados (Módulos 2 y 3) **✅ Migration:** Script creado (idempotente y transaccional) **✅ Documentación:** ADR-017 creado (este archivo) **✅ Módulo 2:** Actualizado con valores diferenciados (150 XP / 30 ML Coins) para reconocer mayor complejidad cognitiva **⏳ Validación:** Pendiente de recrear BD o ejecutar migration **⏳ Testing:** Pendiente de validación funcional post-implementación **Próximo paso:** Ejecutar migration script O recrear base de datos desde seeds actualizados. --- **Estado:** ✅ Aceptado e Implementado **Próxima revisión:** Después de validación en staging **Aprobado por:** Architecture-Analyst **Fecha de aprobación:** 2025-11-24 --- ## Changelog | Versión | Fecha | Cambios | |---------|-------|---------| | 1.0 | 2025-11-24 | Creación inicial del ADR - Decisión de estandarización aprobada e implementada | | 1.1 | 2025-11-28 | Agregada excepción para Módulo 2: 150 XP / 30 ML Coins (mayor complejidad cognitiva). Backend actualizado para usar xp_reward del ejercicio. |