workspace/projects/gamilit/docs/97-adr/ADR-021-estandarizacion-recompensas-xp-ejercicios.md
rckrdmrd ea1879f4ad feat: Initial workspace structure with multi-level Git configuration
- Configure workspace Git repository with comprehensive .gitignore
- Add Odoo as submodule for ERP reference code
- Include documentation: SETUP.md, GIT-STRUCTURE.md
- Add gitignore templates for projects (backend, frontend, database)
- Structure supports independent repos per project/subproject level

Workspace includes:
- core/ - Reusable patterns, modules, orchestration system
- projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.)
- knowledge-base/ - Reference code and patterns (includes Odoo submodule)
- devtools/ - Development tools and templates
- customers/ - Client implementations template

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 10:44:23 -06:00

18 KiB
Raw Blame History

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

-- Todos los ejercicios actualizados a:
-- 150, 30,  ✅ VALORES DIFERENCIADOS (2025-11-28)

Módulo 3 (04-exercises-module3.sql):

-- Ejercicio 3.1 (línea 143):
-- ANTES: 18, 3,
-- DESPUÉS: 100, 20,  ✅ CORREGIDO

Script de Recreación de Base de Datos:

# 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

  • Seeds actualizados con valores estándar (100 XP / 20 ML Coins)
  • 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):

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:

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:

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