# Contexto de trabajo — Evaluación Web RA3 CDT1 (Química)

> Documento generado durante la sesión de análisis e implementación (agente Cline/Kimi).
> Objetivo: que cualquier sesión futura continúe sin repetir la exploración.

## 1. Tarea y requisitos del usuario

Página web para realizar la **evaluación RA3 CDT1 de Química (INTECAP)**, con contenidos y
respuestas tomados de los PDF del directorio. Resultados en CSV: `No,Apellidos,Nombres,Carrera,Nota`.

Requisitos adicionales acordados:
- Pantalla completa obligatoria al iniciar (los navegadores exigen un clic del usuario, por eso
  hay botón "Iniciar evaluación").
- **Anti-trampa, -5 pts por ocurrencia**: salir de pantalla completa, cambiar de pestaña/ventana,
  copiar/pegar, atajos (F12, Ctrl+Shift+I/J/C, Ctrl+U/S/P), DevTools, clic derecho (desde el 2.º).
- **Detector de IA** en preguntas abiertas: umbral de **4+ indicadores** → **-5 pts por bloque
  de 4**. Indicadores: meta ausente, tiempo imposible, teclas insuficientes, estilo formal
  (conectores tipo "asimismo"), redacción copiada del modelo (similitud n-gramas ≥ 0.75).
- Nota final = max(0, académico − 5×incidentes − 5×alertas_ia).

## 2. Fuentes de contenido (directorio local)

- `old/RA3 CDT1 - Examen de Quimica.pdf`: examen completo en texto (100 pts, 5 series).
- `RA3 CDT1 Hoja de Respuestas.pdf`: clave oficial y solucionario.
- `Evaluaciones RA3 CDT1.pdf`: escaneo sin capa de texto (no utilizable).
- Carreras históricas: **Mecánica** y **Electrónica**.

### Estructura y clave (total 100 pts)

| Serie | Tipo | Puntos |
|---|---|---|
| I | V/F ×5 (2 c/u) | 10 |
| II | Selección múltiple ×5 (2 c/u) | 10 |
| III | Preguntas directas ×5 (4 c/u, grupos de palabras clave) | 20 |
| IV | Ejercicios ×7 (4,4,4,4,6,8,10) | 40 |
| V | Diagrama: 18u=4, 4mol=4, moléculas=4, pasos ordenables=8 | 20 |

- Serie I clave: **V V V F V**
- Serie II clave: **B C C B A**
- Serie IV respuestas: 100 u · 5 mol · 132 g · 1.2044e24 moléculas (acepta 12.044x10^23) ·
  %H 11.11 / %O 88.89 · SO2 · C3H6
- Serie V (72 g de agua): 18 u · 4 mol · 2.4088e24 moléculas · 8 pasos ordenados
  (inicio→dato→masa_molecular→moles→conversion→calculo→resultado→fin)
- Masas: H=1 C=12 N=14 O=16 Na=23 S=32 Cl=35.5 Ca=40 · Avogadro 6.022e23

## 3. Arquitectura implementada (módulo dentro del app Flask existente)

Archivos en `/home/adoniz/apps/quimica/` (producción) y copia local en
`/home/adonis/Público/Cursos/Quimica/evaluacion_ra3/`:

| Archivo | Rol |
|---|---|
| `ra3_grader.py` | Dominio puro (sin Flask): clave, calificación por serie, indicadores IA, penalizaciones |
| `ra3_cdt1.py` | Blueprint Flask autocontenido (`template_folder="templates"`): sesiones por token, incidentes, guardado CSV |
| `templates/ra3-cdt1.html` | Página del examen (CSS+JS inline, sin innerHTML/onclick) |
| `test_ra3_grader.py`, `test_ra3_api.py` | 35 pruebas (unittest + Flask test client) — **todas pasan** |
| `prueba_e2e_prod.py` | E2E contra producción por Funnel |
| `patch_app.py`, `patch_app2.py` | Parches idempotentes ya aplicados a `app.py` remoto (verificados con `ast.parse`) |

### Endpoints (relativos a como se monte el blueprint)
- `GET  /ra3-cdt1`     → página del examen
- `POST /iniciar-ra3`  → {apellidos, nombres, carrera∈{Mecánica, Electrónica}} → {token}
- `POST /incidente-ra3`→ {token, tipo} — tipos válidos: pantalla_completa, pestana_oculta,
  ventana_ajena, copiar, pegar, atajo_teclado, devtools, clic_derecho
- `POST /guardar-ra3`  → {token, respuestas{serie1..5}, metas{s3_i:{tiempo_s,teclas,correcciones}}}
  → califica server-side, guarda CSV y devuelve desglose. Doble envío → HTTP 409.

### Seguridad aplicada (skills A-secure-coding / A-coding-standards)
- Allow-list en todos los inputs; límites de longitud (apellidos/nombres 100, textos 500, datos 40).
- Sanitización de floats (NaN/inf rechazados); pasos validados contra lista del dominio.
- CSV: UTF-8 con BOM + escape anti-inyección de fórmulas (=,+,-,@ inicial → prefijo `'`).
- Sin innerHTML/onclick en el cliente; fetch con URLs **relativas** (funciona en cualquier montaje).
- Sesión por token `secrets.token_hex(16)` con `threading.Lock`; envío único.
- La clave de respuestas vive SOLO en el servidor (ra3_grader.py).

<!-- PARTE-2 -->

## 4. Entorno de producción (verificado)

```bash
ssh adoniz@192.168.0.150        # llave SSH configurada, funciona sin contraseña
hostname: adoniz-acer · Tailscale IP: 100.124.60.90 · Python 3.11.2 · Flask 2.2.2
```

- App: `/home/adoniz/apps/quimica/app.py` (Flask, `host 0.0.0.0`, **puerto 8081**), corre en
  `screen` con nombre **quimica**: `screen -dmS quimica bash -c 'python3 app.py >> app.log 2>&1'`.
- Módulos previos: `/ra2-cdt1`, `/masas-moleculares`, etc. y `POST /guardar` → `notas_quimica.csv`.
- **Tailscale Funnel**: `https://adoniz-acer.tail60dd6a.ts.net`
  - `/` → proxy `127.0.0.1:8080` (gateway aparte con `/login`, propiedad de otro proceso/usuario)
  - `/quimica` → proxy `127.0.0.1:8081` (añadido en esta sesión con
    `tailscale funnel --bg --set-path=/quimica http://127.0.0.1:8081`)
- ⚠️ **Tailscale elimina el prefijo** al reenviar: `/quimica/ra3-cdt1` llega al backend como
  `/ra3-cdt1`. Por eso el blueprint se registra **sin** url_prefix y las llamadas fetch del
  cliente son relativas. Estado actual de app.py: `app.register_blueprint(ra3_bp)` (sin prefijo).
- ⚠️ Al ejecutar `tailscale serve --bg --set-path=...` se perdió temporalmente el modo Funnel;
  se restauró con `tailscale funnel --bg --set-path=/ ...8080` y `...--set-path=/quimica ...8081`.
- nginx corre (puerto 80 default, sin vhosts que interesen); no enruta nada de estas apps.

## 5. Resultados de verificación (2026-08-27)

- **35/35 pruebas unitarias+integración OK** (local, Python 3.12/Flask 3.0).
- E2E producción por Funnel: examen perfecto → `academico=100`, con 1 incidente →
  `nota_final=95`; reenvío bloqueado (409); CSV generado con formato
  `No,Apellidos,Nombres,Carrera,Nota` (BOM UTF-8, acentos correctos, correlativo automático).
- CSVs de prueba **eliminados** en producción: arranca limpio para los estudiantes.
- Página pública verificada: `https://adoniz-acer.tail60dd6a.ts.net/quimica/ra3-cdt1` → 200.
- Acceso LAN alternativo: `http://192.168.0.150:8081/ra3-cdt1` (200).

## 6. Cómo operar

```bash
# Reiniciar el servicio tras cambios:
ssh adoniz@192.168.0.150 'screen -S quimica -X quit; cd /home/adoniz/apps/quimica && \
  rm -rf __pycache__ && screen -dmS quimica bash -c "python3 app.py >> app.log 2>&1"'
# Notas acumuladas (formato Excel-friendly, UTF-8 BOM):
/home/adoniz/apps/quimica/resultados_ra3_cdt1.csv
# Auditoría de trampas:
/home/adoniz/apps/quimica/incidencias_ra3_cdt1.csv  (fecha, token8, estudiante, tipo)
```

## 7. Supuestos y limitaciones

- La pantalla completa requiere el clic del botón Iniciar (restricción de navegadores).
- La detección de IA es heurística: el detalle de indicios queda en pantalla para el docente y
  el umbral de 4 indicadores minimiza falsos positivos; la nota puede ajustarse a mano en el CSV.
- Ningún sistema web evita trampas fuera del navegador (p. ej. teléfono aparte).
- El gateway del puerto 8080 (con /login) pertenece a otro proyecto; no se tocó.
- Archivos auxiliares pendientes de borrar si se desea: `/tmp/app_local.py`, `/tmp/prueba_e2e.py`,
  `/tmp/pagina.html` (locales) — no afectan producción.

## 8. Ciclo MVP → QA (2026-08-27, segunda iteración)

- **Bug reportado por el docente**: el menú `/quimica/` no mostraba RA3. Causa: `index.html`
  es estático; se insertó la tarjeta (parche `patch_index.py`) y se reinició el servicio.
- **QA SAQI** (`qa_funnel.py` contra producción): 21/21 PASS en 2.ª ejecución
  (502 inicial = handshake transitorio de Tailscale, no bug).
- **QA-001 corregido**: detector de ventana ajena inerte (`activeElement` ≠ body siempre al
  escribir). Ahora reporta directo con enfriamiento 3 s + gracia 2 s tras fullscreen.
- Informe completo: `evaluacion_ra3/qa_informe.md`.
- Estado final: menú visible ✅ · Funnel 200 ✅ · 35/35 unit+int ✅ · 21/21 QA producción ✅.

## 9. Ciclo QA-004/005 — Modal, evidencias en video y limpieza (tercera iteración)

- **QA-004 (bug del docente)**: `confirm()` nativo robaba el foco → contaba `ventana_ajena`
  al enviar con preguntas en blanco. Sustituido por **modal en la página** (Aceptar/Cancelar):
  Cancelar regresa sin sancionar; Aceptar guarda y las blancas valen 0 (nunca incursiona el
  foco; `reportarIncidente` ignora mientras `enviando`). Desplegado en producción.
- **Pruebas E2E con evidencia en video** (`e2e_video/`), **headless y perfil aislado**
  (no reacciona a tareas/foco del equipo), a **ritmo humano slowMo 450 ms**:
  - `tests/evidencia.spec.js`: E1 ejemplar=100 ✅ · E2 tramposo→incidentes y modal ✅ ·
    E3 reprobado <60 ✅. Resultado **3/3 passed**.
  - Videos en `e2e_video/salidas/evidencia-*/video.webm`; reporte en `reportes-html/`.
- **CSV de producción reseteado a solo encabezado** tras la prueba (obligatorio para que el
  primer estudiante real arranque limpio).
- Detalle completo en `evaluacion_ra3/qa_informe.md` (sección 5 y 6).

## 10. Módulo adicional: Reacciones Químicas (4.1)

### Descripción
Módulo de aprendizaje sobre reacciones químicas con teoría, evaluación interactiva y calificación automática. Incluye 4 temas con 25 puntos totales.

### Temas
- 4.1.1 Concepto de reacción química (1 h, 5 pts)
- 4.1.2 Evidencias de las reacciones químicas (1 h, 5 pts)
- 4.1.3 Representación simbólica de las reacciones (1 h, 5 pts)
- 4.1.4 Clasificación de las reacciones químicas (3 h, 10 pts)

### Sistema de calificación
- **Nota unificada**: Se suman los puntos obtenidos y se divide entre 25, multiplicando por 100
- Anti-trampa: −5 pts por incidente (cambio pestaña, copiar/pegar, atajos, etc.)
- Nota final = max(0, nota académica − 5 × incidentes)

### Archivos
- `reacciones_config.py`: Configuración central
- `reacciones_cdt.py`: Blueprint Flask
- `reacciones_grader.py`: Dominio puro de calificación
- `templates/reacciones-quimicas.html`: Página autocontenida

### URLs de producción
- Funnel: `https://adoniz-acer.tail60dd6a.ts.net/quimica/reacciones-quimicas`
- LAN: `http://192.168.0.150:8081/reacciones-quimicas`

### QA
- 32/32 pruebas unitarias+integración pasan
- 19/19 pruebas funnel pasan en producción
- Informe detallado en `reacciones_quimicas/qa_informe.md`

