# Tareas para Kimi - Sprint 2 🏃‍♂️ *(Math2 Platform - Fixes Post-Remediación)* Kimi, tu informe anterior (`INFORME_FINAL_REMEDIACION.md`) muestra gran progreso, pero debido a los cambios en el cliente de Prisma y las relaciones, introdujiste **4 regresiones en los tests de integración del backend** (`tests/integration/exercise.integration.test.ts`). Tu objetivo para este sprint corto es solucionar estos bloqueantes y dejar el suite de tests 100% en verde. --- ## 🛑 BUGS A RESOLVER (Prioridad P0) ### 1. Fix en Ranking Global (`Argument moduleId must not be null`) - **Archivo:** `backend/src/modules/ranking/ranking.service.ts` (aprox. línea 229) - **El Problema:** Al buscar la posición global del usuario, estás enviando `moduleId: null` dentro de un `prisma.ranking.findUnique`. Las versiones recientes de Prisma restringen las búsquedas `findUnique` en índices compuestos si un campo es nulo. - **La Solución:** Cambia la llamada lógica de `findUnique` a `findFirst`. ```typescript // Cambiar esto: const previousGlobal = await prisma.ranking.findUnique({ where: { userId_moduleId: { userId, moduleId: null } } }); // Por esto: const previousGlobal = await prisma.ranking.findFirst({ where: { userId, moduleId: null } }); ``` ### 2. Race Condition en Envíos Concurrentes (`AttemptNumber`) - **Archivo:** `backend/src/modules/exercise/exercise.service.ts` (método `submitAttempt`) - **El Problema:** El test de "Concurrent submission handling" lanza un error **Unique constraint failed** en `(userId, exerciseId, attemptNumber)`. Actualmente estás contando los intentos previos (`prisma.exerciseAttempt.count`) *fuera* de la transacción principal. Si 5 requests entran a la vez, todos leen un count de `0`, usan `attemptNumber = 1` y chocan en la inserción. - **La Solución:** Mueve el conteo de los intentos previos (y por consecuencia, la variable `attemptNumber`) **DENTRO** del bloque `await prisma.$transaction(async (tx) => { ... })`. - Asegúrate de usar `tx.exerciseAttempt.count` en su lugar. - Al contar dentro de la transacción serializable, Prisma garantizará el aislamiento y la correctitud del número. - Ojo: la lógica completa de feedback y `ScoreCalculator.calculate` también deberán estar dentro o ajustarse, porque dependen del `attemptNumber` final. ### 3. Aserciones de Paginación Rotas en Tests - **Archivo:** `backend/tests/integration/exercise.integration.test.ts` (Línea 312) - **El Problema:** El test intenta leer `response.body.data.attempts.length`. Sin embargo, la refactorización reciente del Endpoint `GET /api/exercises/:id/attempts` devolvió el array directamente en la raíz de `data` (y la bandera `hasCompleted` se movió a la llave `meta`). - **La Solución:** Cambiar las expectativas en el test para que coincidan con la firma actual del Controller: ```typescript // Viejo test expect(response.body.data.attempts.length).toBeGreaterThanOrEqual(1); expect(response.body.data.hasCompleted).toBe(true); // Nuevo test expect(response.body.data.length).toBeGreaterThanOrEqual(1); expect(response.body.meta.hasCompleted).toBe(true); ``` *(Nota: O si prefieres, revierte la respuesta del Controller a devolver la llave `attempts` dentro de `data` si ese era el contrato de API original)*. --- ## 🧹 TAREAS MENORES (Prioridad P1) - Ejecuta `npm run test` y valida que pases los **123 tests** sin arrojar `PrismaClientValidationError` o `AssertionError`. - Verifica qué dependencias rotas quedan reportadas en `npx tsc --noEmit` después de arreglar estos 3 puntos. ¡A por el cierre del Backend, Kimi!