# 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!
