Reporte de Impulso Lector
El panel donde el profesor ve lo que sus alumnos hicieron en las cápsulas de
Impulso Lector: quién las hizo, qué entendió y cómo lee
—con la grabación y cada palabra marcada—. Es el
resultados.php que pide la especificación del backend, diseñado: cómo
se llega, qué muestra y cómo lo muestra.
1De dónde parte
De la especificación «WClass Publisher · Backend de resultados de alumnos»
(v1.5, 2 sep 2026). Define cómo se guardan los resultados: cinco tablas
(lc_capsula, lc_pregunta, lc_result_attempt,
lc_result_answer, lc_result_file), un endpoint idempotente con la identidad
tomada de la sesión, y el MP3 en disco. De la pantalla del profesor dice una línea:
«filtros por colegio / curso / cápsula / alumno, escuchar audio, ver el detalle por pregunta y
exportar». Este documento es esa línea.
Y de lo que ya existe, relevado en el código el 2026-09-28:
- El visor de cápsulas (
proyectoweb/lectore/creador_lib.php, 10.494 líneas) ya tiene un «Ver reporte»: una tabla por pregunta con Correcto / Incorrecto, chips de lectura y un reproductor con la onda y los errores en rojo. Pero vive sólo en el navegador (IndexedDBlcpReport), no sabe quién es el alumno («Anónimo») y no guarda elo.idde la pregunta. - Desafío Lenguaje en el producto ya tiene reportes en Laravel
(
Desafio\ReportesLecturaController,resources/js/components/reportes-lenguaje/): un tablero por nivel y curso, un informe alumno × indicador agrupado por habilidad, y una ficha de alumno con donas por habilidad. El reporte nuevo se arma con ese mismo lenguaje, para que el profesor no aprenda dos. - No hay nada de Impulso Lector, fluidez ni palabras por minuto en ninguno de los dos repos del producto. Y en esta máquina no hay ninguna cápsula de Desafío Lenguaje: las de la maqueta son de ejemplo.
2Lo que hay que corregir en la especificación del backend
Contrastada con el código, la especificación tiene diferencias concretas. Ninguna cambia la arquitectura, pero todas cambian lo que el reporte puede mostrar. Conviene resolverlas antes de migrar, porque después son datos que no se guardaron.
alumno no es la persona
La especificación pone claves foráneas a alumnos, cursos y
colegios. En el producto son alumno, curso y
colegio, en singular (modelos App\Student, App\Curso,
App\School).
Y alumno.id no identifica a la persona: es su inscripción en un
curso y un año (alumno.alumno → usuario.id, más
curso, colegio, anio, nivel). Eso le conviene
al diseño —lc_result_attempt.alumno_id apuntando a alumno.id
ya es el snapshot de curso y año—, pero hay que saberlo: el historial de un
niño a lo largo de los años se arma por alumno.alumno, no por
alumno_id. Todos los resultados del producto (test_alumno,
resultados, desafio_indicador_alumno) usan alumno.id.
De la sesión: para un alumno, controladorTema.php:34-36 ya deja
$_SESSION['alumno'] con su alumno.id. Si no está, la consulta de
desafiocrece/Daos/Trainer.php:490-499 lo resuelve desde usuario, nivel,
colegio y año.
El visor graba con MediaRecorder y el blob sale como
rChunks[0].type || 'audio/webm'. lc_result_file.mime tiene que aceptar
audio/webm (o convertir en el servidor), y la validación «tipo real del archivo»
tiene que reconocerlo.
Y en un teléfono con el reconocimiento del navegador el visor no graba
(if(!rMobile) rStartAudio();): el reconocimiento y la grabación compiten por el
micrófono. La lectura se mide igual, pero no hay archivo. El reporte tiene que decir
«sin grabación» en vez de mostrar un reproductor vacío —la maqueta lo hace—.
Con Vosk (el motor local que se usa en Android) sí se graba.
lcpAlignWords alinea lo dicho con el texto y marca cada palabra: ok,
sub (dijo otra), del (la saltó), ins (agregó
una). Con eso calcula la precisión… y no lo guarda: el reporte del visor
sólo conserva posiciones en la onda (errMarks).
Sin eso, el profesor escucha dos minutos de audio sin saber dónde mirar. Tiene que ir en
lc_result_answer.metricas, que ya es JSON:
{ "ppm": 84, "precision": 91, "fluidez": 75, "categoria": 2, "grado": 3,
"motor": "webspeech", "con_audio": true,
"ops": [ {"w":"Una","op":"ok"}, {"w":"mañana","op":"sub","dijo":"maña"},
{"w":"zorro","op":"del"}, {"op":"ins","dijo":"este"}, ... ],
"sub": 4, "del": 2, "ins": 1, "gap": 0 }
Pesa poco (un texto de 80 palabras son ~3 KB) y es lo que hace útil la ficha.
La especificación nombra «emparejar, arrastrar, zonas, ordenar». Esas son las
etiquetas; los qtype reales (creador.js:1418) son
matching, dnd / dndmulti, hotspot y
ordering. Y la lectura no es un tipo sino dos: reading y
readingspeed. Son 21 en total. lc_pregunta.tipo tiene que guardar el
literal, no la etiqueta.
- Cada pregunta es correcta o incorrecta; no hay puntos.
puntajeypuntaje_maxquedarán en 1/0 hasta que el editor los ofrezca. El reporte usa % de preguntas correctas. - Ninguna pregunta declara su habilidad (localizar, interpretar, reflexionar) ni su OA. El reporte por habilidad —que es como Desafío Lenguaje ya reporta— necesita una columna nueva, ver §8.
- Los
o.idno tienen un formato único (o_14,o_read1,o3,lc_new_id('obj')). La clave(capsula_id, pregunta_uid)sirve igual, siempre que duplicar una diapositiva genere ids nuevos: hay que comprobarlo, porque dos preguntas con el mismoo.iden una cápsula se pisarían en el catálogo.
3Quién lo usa
- El profesor (rol 13): ve sólo sus cursos —los de
curso_profesory su jefatura—. - UTP y director (12, 11): todos los cursos del colegio. Son los mismos
ALLOWEDROLES = [11, 12, 13]de los componentes de Desafío Lenguaje.
informeDesafioMate/daos/informeDao.php:33-43 (obtenerCursos) trae
todos los cursos del nivel, sin filtrar por profesor. Un profesor puede ver los resultados
de un curso que no es suyo. Y las rutas de reportesLectura/*
(routes/api.php:1809-1863) no tienen middleware de autenticación. En este
reporte, cada consulta comprueba en el servidor que el curso es del usuario de la
sesión, igual que el action=audio de la especificación.
4Dónde vive y cómo se llega
En Laravel, en el módulo de Desafío Lenguaje, junto a los reportes de lectura que
ya existen: un componente Vue nuevo bajo reportes-lenguaje/ y sus rutas en
Desafio\ReportesLecturaController (o uno propio), leyendo las tablas lc_*
que están en la misma base. La especificación propone un resultados.php suelto;
hacerlo en Laravel le da el marco, el login y el estilo que el profesor ya conoce. El endpoint que
recibe los resultados (resultados_api.php) puede quedar donde la
especificación lo pone: es el que necesita ser same-site con la cápsula.
Se entra directo al reporte, con el primer curso del profesor (su jefatura) y todas las cápsulas del año. No hay una pantalla intermedia de cursos: el curso se cambia con el selector, y la maqueta arranca ahí.
Tres caminos de entrada
- Desde la portada: el bloque Desafío Crecer (
includes/link-desafio.php) → Desafío Lenguaje (el POST aloginFromWebclassque ya existe) → Impulso Lector. Sólo si el colegio lo tiene encolegio_plan_desafio. - Desde el menú de Desafío Lenguaje, como una opción más. Los nombres del submenú de la maqueta son propuesta.
- Desde la cápsula: cuando la abre un profesor, el botón «Ver reporte» del visor lleva a este reporte con esa cápsula elegida y en la pestaña Preguntas, en vez de mostrar el reporte local del navegador (que para el profesor está vacío: no es él quien la resolvió).
5Qué muestra
El reporte de un curso
Filtros en este orden: año —primero, porque acota todo lo demás: qué cursos tiene el profesor ese año y qué cápsulas se asignaron—, curso y cápsula (una, o todas; la lista va de la más reciente a la más antigua, con su fecha de asignación).
No lleva tarjetas de cifras arriba. Los números están en los reportes, donde se pueden leer con su contexto; un resumen suelto encima de la tabla compite con ella y no dice qué hacer. El contenido ocupa todo el ancho de la pantalla.
La tabla distingue completaron · abrieron y no terminaron · no la abrieron. Las dos
últimas sólo se pueden separar con el action=start que la especificación
deja opcional: hay que hacerlo.
Un toque en el título ordena de menor a mayor; el segundo, al revés; una flecha dice el sentido. Se ordena por el valor, no por el texto: 9% va antes que 60%, «Muy lenta» antes que «Lenta», y los nombres por apellido sin que las tildes los saquen de su letra. Lo que no tiene dato —«sin abrir», sin lectura— va siempre al final, en los dos sentidos: no es ni lo más bajo ni lo más alto. El orden elegido se mantiene al cambiar de curso.
Los números cortos (porcentajes, palabras por minuto, intentos) van centrados en su columna.
En septiembre un curso lleva 12 a 14 cápsulas: una columna por cápsula no cabe en la pantalla. La tabla se desplaza dentro de su caja (la página no se ensancha), de la cápsula más antigua a la más reciente, y quedan fijos el número y el nombre del alumno a la izquierda y su comprensión promedio y su última lectura a la derecha: al desplazar no se pierde de quién es cada fila. El encabezado de cada cápsula lleva su fecha y el título en dos líneas.
Las pestañas Preguntas, Lectura y Habilidades aparecen sólo con una cápsula elegida. Mezclar las preguntas de catorce cápsulas no dice nada, y una pestaña que obliga a elegir antes de mostrar algo parece vacía.
Con una cápsula elegida, cuatro pestañas:
| Pestaña | Qué responde | Cómo |
|---|---|---|
| Alumnos | ¿Quién la hizo y cómo le fue? | Una fila por alumno. Con una cápsula: estado, comprensión, ppm, fluidez, precisión, intentos y fecha. Con todas: una columna por cápsula (comprensión y ppm), como el informe de avance de Desafío Mate. Se ordena por columna. |
| Preguntas | ¿Qué se entendió y qué no? | Una tarjeta por pregunta, en el orden de la cápsula: tipo, diapositiva, habilidad, % correcto y qué se eligió en cada alternativa —con la miniatura si la alternativa es imagen—. Las abiertas muestran sus respuestas. |
| Lectura en voz alta | ¿Cómo lee el curso? | La tabla de fluidez del grado, el reparto del curso en las seis categorías, y una fila por alumno de la más lenta a la más rápida: ppm, categoría, precisión, palabras cambiadas, omitidas, duración y «Escuchar». Con todas las cápsulas, la evolución de cada alumno. |
| Habilidades | ¿En qué tipo de pregunta falla? | Una dona por habilidad para el curso y una tabla alumno × habilidad, con «Reforzar: …» en la que está bajo. Es el mismo formato de donas de la ficha de Desafío Lenguaje. |
La ficha del alumno
- Su comprensión, palabras por minuto, categoría y tiempo en la cápsula. Selector de cápsula y, si la hizo más de una vez, de intento, diciendo cuál cuenta.
- Su lectura: el audio con la onda y las marcas de error, y el texto con cada palabra marcada —la que cambió (con lo que dijo encima), la que saltó, la que agregó—. Al reproducir, se ilumina la palabra que suena. Si leyó en un teléfono y no hay grabación, se dice, y el texto marcado sigue ahí.
- Sus respuestas, una por pregunta: lo que marcó (la etiqueta legible del visor,
lcpAnswerText, con miniatura si es imagen), ✓ o ✗, la correcta si se equivocó, cuántos intentos, y las marcas de clave anterior o pregunta retirada. - Su lectura durante el año, una cápsula tras otra, en un gráfico con la franja de «medio alta o más».
- «Imprimir / PDF»: sale sólo la ficha, con una cabecera que dice colegio, curso,
número de lista, cápsula, intento y fecha de impresión —en pantalla eso lo
dicen los selectores, que en el papel no van—. El audio no se imprime; el texto con las
palabras marcadas sí, que es lo que el profesor lleva a una reunión de apoderados o
al equipo PIE. Es el
window.print()del navegador, que también guarda en PDF: no hace falta generar el PDF en el servidor.
Exportar
CSV con punto y coma y BOM —el mismo formato del «Ver reporte» del visor, que el Excel en español abre bien—: una fila por alumno y pregunta, con habilidad, respuesta, correcta, resultado, si se calificó con la clave actual o la anterior, y las métricas de lectura. Respeta los filtros.
6Cómo lo muestra: las reglas
El visor calcula un solo «logro» de lectura: Math.round(prec*0.6 + flu*0.4). En el
reporte eso no se usa. Un alumno que lee rápido y no entiende y uno que entiende y lee lento
sacan el mismo número, y necesitan cosas opuestas. La comprensión es el % de
preguntas correctas que se corrigen solas (sin la lectura en voz alta y sin las abiertas);
la fluidez son las palabras por minuto y su categoría. En la maqueta hay alumnos al
100% en una y en «muy lenta» en la otra.
- La fluidez usa la tabla que ya usa el visor (
LCP_READ_FLUENCY,creador_lib.php:5356, «estándar Mineduc / Fundación Arauco»), con sus seis categorías y sus colores: rojo las lentas, ámbar las medias, verde las rápidas. Para 3° básico: <64, 64, 76, 88, 100, 112. - Las cifras de la fluidez cuentan alumnos, por su última lectura, no lecturas sueltas. En una versión anterior de la maqueta dos pantallas contaban distinto y decían «5 lentos» y «11 lentas» del mismo curso: eso basta para que el profesor no le crea a ninguna. Un solo cálculo, en todas partes.
- Tramos de comprensión: bajo <60%, en proceso 60-79%, logrado ≥80%. Ver §10: el producto tiene tres escalas distintas.
- El intento que cuenta es el último completado. Los otros se ven en la ficha.
- Las abiertas no puntúan: se muestran, no se corrigen solas, y no entran en la comprensión.
- La lectura se ordena de la más lenta a la más rápida: arriba está lo que hay que escuchar.
- Cada cápsula tiene su texto: el cambio de ppm entre una y otra es una pista, no una medición exacta, y la pantalla lo dice.
Revisiones de la clave y preguntas retiradas
Es la tabla «Edición de preguntas y revisiones» de la especificación, llevada a la pantalla:
- Una pregunta con respuestas calificadas contra otra revisión de la clave
(
pregunta_rev < rev) muestra cuántas son, cuál era la clave anterior, y el botón «Re-evaluar esta pregunta». El botón dice antes cuántas respuestas suben y cuántas bajan, re-evalúa en todos los cursos (la clave es de la cápsula, no del curso), y deja registro de quién y cuándo. Nada se re-califica solo. - Una pregunta retirada (
vigente = 0) sigue apareciendo para quienes la respondieron, tachada y con la fecha en que se sacó.
7Las consultas que sostienen la pantalla
Dos que conviene escribir una vez y reusar, porque todo el reporte depende de ellas:
-- El intento que cuenta: el último completado de cada alumno en la cápsula
SELECT a.*
FROM lc_result_attempt a
JOIN (SELECT alumno_id, MAX(finalizado_en) f
FROM lc_result_attempt
WHERE capsula_id = ? AND estado = 'completado' AND curso_id = ?
GROUP BY alumno_id) u
ON u.alumno_id = a.alumno_id AND u.f = a.finalizado_en
WHERE a.capsula_id = ?;
-- Los alumnos del curso, con quien no la abrió (LEFT JOIN, no JOIN)
SELECT al.id, ud.nombre_usuario, ud.apellido_paterno, ...
FROM curso c
JOIN alumno al ON al.curso = c.id AND al.estado = 1 AND al.habilitado = 1
JOIN usuario u ON u.id = al.alumno AND u.idrol = 31
JOIN usuario_detalle ud ON ud.idusuario = u.id
LEFT JOIN lc_result_attempt t ON t.alumno_id = al.id AND t.capsula_id = ?
WHERE c.id = ?;
La segunda sigue el patrón de informeDesafioMate/daos/informeDao.php:186-201.
Con MySQL 8.4 (relevado para el gadget 01) la primera se puede escribir también con
ROW_NUMBER().
8Lo que hay que agregar al modelo
| Dónde | Qué | Por qué |
|---|---|---|
lc_pregunta | habilidad VARCHAR(32) NULL — 'localizar', 'interpretar', 'reflexionar' nueva |
Sin ella no hay pestaña de habilidades. Se elige en el editor, por pregunta; la
sincronización del catálogo la copia desde creador.json. |
lc_pregunta | oa VARCHAR(32) NULL nueva |
Opcional hoy; es lo que permitiría cruzar con el informe de aprendizaje. |
lc_result_answer.metricas | las ops palabra por palabra, sub/del/ins, motor, con_audio |
§2. Es lo que marca el texto en la ficha. |
lc_result_file.mime | aceptar audio/webm | §2. |
lc_reevaluacion | (pregunta_id, rev_desde, rev_hasta, respuestas, suben, bajan, usuario_id, creado_en) nueva |
El «dejando registro» de la especificación: sin tabla, no hay dónde. |
9Criterios de aceptación
- Se llega desde la portada (Desafío Crecer → Desafío Lenguaje → Impulso Lector) directo al reporte, y desde la cápsula con ella elegida.
- Los filtros van en el orden año, curso, cápsula.
- Con «Todas» y 14 cápsulas, la tabla se desplaza dentro de su caja; el alumno y sus promedios quedan fijos y la página no se ensancha.
- Las pestañas Preguntas, Lectura y Habilidades sólo aparecen con una cápsula elegida.
- Todas las tablas se ordenan por cualquier columna, por valor, con lo vacío al final.
- La ficha se imprime sola, con su cabecera, sin el marco ni el reproductor.
- Un profesor ve sólo sus cursos; la comprobación es del servidor, no de la pantalla.
- Completaron + abrieron sin terminar + no la abrieron = los alumnos del curso.
- En una pregunta de opción única, las barras suman las respuestas; en una alternativa-imagen se ve la imagen.
- La comprensión no incluye la lectura en voz alta ni las abiertas.
- La fluidez se clasifica con la tabla del grado, en las seis categorías del visor.
- En la ficha, las palabras marcadas coinciden con los conteos y la precisión sale de ellas.
- Sin grabación, se dice; con grabación, se escucha y sólo la sirve
action=audiocon permiso. - Las respuestas con clave anterior se marcan; «Re-evaluar» dice cuántas suben y bajan, lo hace y deja registro.
- Una pregunta retirada sigue visible para quien la respondió, marcada.
- Con dos intentos, cuenta el último completado y la ficha deja ver el otro.
- El CSV respeta los filtros y abre bien en Excel en español.
10Qué hay que decidir antes de programar
- Los tramos de logro. El producto tiene tres escalas: el informe de evaluación
(
informes/general.php: <60 / 60-81 / >82, con huecos en 60, 81 y 82), el informe de indicadores de Desafío Lenguaje (≤20% «bajo promedio») y la ficha de Desafío Lenguaje (0-30 / 31-80 / 81-100). La maqueta usa 60 / 80. Tiene que ser una. - ¿Palabras dichas o palabras correctas por minuto? El visor calcula
A.saidTotal / minutos: cuenta también las que leyó mal y las que agregó. Las normas de velocidad lectora suelen medir palabras leídas correctamente. Hay que confirmar contra qué midió la tabla, porque con la cuenta actual un alumno que se equivoca mucho puede caer en una categoría más alta de la que le corresponde. En la maqueta pasa: una alumna lee 116 palabras por minuto, «muy rápida», con 73% de precisión y 11 palabras omitidas. - ¿El grado de la norma es el del alumno o el de la cápsula? La maqueta usa el del alumno (su curso): un niño de 4° que lee una cápsula de 3° se mide contra 4°. El visor hoy toma el de la cápsula.
- ¿Cuenta el último intento o el mejor? La maqueta usa el último completado.
- ¿El profesor puede corregir las abiertas? Hoy no puntúan. Si se corrigen a mano, necesitan dónde guardar esa nota.
- La entonación está desactivada en el visor (
wantProsody=false): no se muestra hasta que se active y se valide. - La retención del audio, que la especificación ya deja abierta, define si la ficha puede mostrar lecturas del año anterior.
Los resultados son de ejemplo, generados con semilla fija —siempre los mismos— para dos cursos de 3° básico y catorce cápsulas con textos propios, de marzo a septiembre. Las tres de septiembre son las completas (una versión propia de la fábula del zorro y el gallo, un texto informativo sobre el pingüino de Humboldt y la leyenda del Caleuche); las once anteriores traen la lectura y tres preguntas. La voz del reproductor es sintética: el navegador lee lo que el alumno dijo, a su ritmo. Las alternativas-imagen son dibujos de reemplazo de las imágenes de la cápsula.
Atajo: ?capsula=c1 (o c2, c3) entra con una
cápsula elegida, que es como llega el «Ver reporte» de la cápsula. En
c1 está la pregunta con la clave corregida; en c2, la retirada.