feat: fase 2+3 — expansion masiva multi-perfil + bug fixes + hardening
Fase 2 (expansion): - Francesca: +6 etapas matematicas (5-10), +7 etapas lectura (3-9), +2 ortografia - Sebastian: +8 etapas matematicas (4-11), +6 lectura, +3 historia, +3 geografia, +1 banderas - Nuevas paginas: ortografia, lectura, geografia, matematicas - ~900 ejercicios nuevos, paridad ~500 por perfil Fase 3 (bug fixes + hardening): - Fix: SessionLog auto-create en grade route - Fix: engine cache (no borrar antes de revisar) - Fix: FSRS cards actualizadas en flujo curriculum - Fix: responseMs real (no hardcodeado 3000) - Fix: options dentro de content en sebastian etapa-1 - Fix: trazo-letra consonantes crash - Security: execFileSync anti-command-injection en TTS - DB: 18 cascade deletes + indices + unique constraints - APIs debug: reset, state, seed - Docker: espeak-ng + prisma + user/group - E2E: 23 tests nuevos (curriculum-flow.spec.ts) - Code review: tailwind colors, middleware dev mode, eslint config Verificado: tsc exit 0, build exit 0, 61 E2E tests pass
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
import type { Stage } from "../types"
|
||||
|
||||
const cuentos = [
|
||||
{
|
||||
titulo: "El patito feo",
|
||||
secuencia: [
|
||||
"Un patito nació diferente a sus hermanos.",
|
||||
"Todos se burlaban de él por ser distinto.",
|
||||
"El patito se fue triste a vivir solo.",
|
||||
"Creció y se convirtió en un hermoso cisne.",
|
||||
"Todos los patos lo admiraban por su belleza.",
|
||||
],
|
||||
orden: [0, 1, 2, 3, 4],
|
||||
emoji: "🦆",
|
||||
},
|
||||
{
|
||||
titulo: "La liebre y la tortuga",
|
||||
secuencia: [
|
||||
"La liebre se burlaba de la tortuga por lenta.",
|
||||
"La tortuga la desafió a una carrera.",
|
||||
"La liebre salió corriendo muy rápido.",
|
||||
"La liebre se confió y se durmió.",
|
||||
"La tortuga pasó a la liebre y ganó la carrera.",
|
||||
],
|
||||
orden: [0, 1, 2, 3, 4],
|
||||
emoji: "🐢",
|
||||
},
|
||||
{
|
||||
titulo: "Los tres chanchitos",
|
||||
secuencia: [
|
||||
"Tres chanchitos construyeron sus casas.",
|
||||
"Uno la hizo de paja, otro de madera y otro de ladrillos.",
|
||||
"El lobo sopló y derribó la casa de paja.",
|
||||
"El lobo sopló y derribó la casa de madera.",
|
||||
"El lobo no pudo derribar la casa de ladrillos.",
|
||||
],
|
||||
orden: [0, 1, 2, 3, 4],
|
||||
emoji: "🐷",
|
||||
},
|
||||
{
|
||||
titulo: "La cigarra y la hormiga",
|
||||
secuencia: [
|
||||
"La cigarra cantaba todo el verano sin trabajar.",
|
||||
"La hormiga juntaba comida para el invierno.",
|
||||
"Llegó el invierno y la cigarra no tenía comida.",
|
||||
"La cigarra fue a pedirle comida a la hormiga.",
|
||||
"La hormiga le dio comida pero le enseñó a trabajar.",
|
||||
],
|
||||
orden: [0, 1, 2, 3, 4],
|
||||
emoji: "🐜",
|
||||
},
|
||||
]
|
||||
|
||||
const exercises: any[] = []
|
||||
let idx = 0
|
||||
|
||||
for (const cuento of cuentos) {
|
||||
// Part 1: ordenar secuencia (secuencia type)
|
||||
const shuffled = [...cuento.orden].sort(() => Math.random() - 0.5)
|
||||
exercises.push({
|
||||
id: `fra9-secuencia-${idx}`,
|
||||
stage: 9,
|
||||
skillCode: `secuencia-cuento-${idx}`,
|
||||
type: "secuencia",
|
||||
prerequisites: idx === 0 ? [`fra8-sinonimo-24`] : [exercises[idx - 1].id],
|
||||
content: {
|
||||
instruction: `Ordená los eventos de "${cuento.titulo}"`,
|
||||
text: cuento.secuencia.join(". "),
|
||||
audioText: `Ordená los eventos del cuento ${cuento.titulo}`,
|
||||
emoji: cuento.emoji,
|
||||
sequence: shuffled.map((s) => cuento.secuencia[s]),
|
||||
},
|
||||
functionalContext: "Ordenar eventos de un cuento clásico en secuencia narrativa.",
|
||||
errorType: "omision-letra",
|
||||
})
|
||||
idx++
|
||||
|
||||
// Part 2: comprensión (lectura type) — 2 preguntas por cuento
|
||||
const preguntas = cuento.titulo === "El patito feo"
|
||||
? [
|
||||
{ q: "¿Cómo nació el patito?", op: ["Diferente", "Igual", "Más grande"], correcta: "Diferente" },
|
||||
{ q: "¿En qué se convirtió?", op: ["Cisne", "Pato", "Ganso"], correcta: "Cisne" },
|
||||
]
|
||||
: cuento.titulo === "La liebre y la tortuga"
|
||||
? [
|
||||
{ q: "¿Quién ganó la carrera?", op: ["La tortuga", "La liebre", "Las dos"], correcta: "La tortuga" },
|
||||
{ q: "¿Por qué perdió la liebre?", op: ["Se durmió", "Corrió lento", "Se perdió"], correcta: "Se durmió" },
|
||||
]
|
||||
: cuento.titulo === "Los tres chanchitos"
|
||||
? [
|
||||
{ q: "¿Qué casa no pudo derribar el lobo?", op: ["La de ladrillos", "La de paja", "La de madera"], correcta: "La de ladrillos" },
|
||||
{ q: "¿De qué hizo la casa el primer chanchito?", op: ["Paja", "Madera", "Ladrillos"], correcta: "Paja" },
|
||||
]
|
||||
: [
|
||||
{ q: "¿Qué hizo la cigarra en verano?", op: ["Cantar", "Trabajar", "Dormir"], correcta: "Cantar" },
|
||||
{ q: "¿Qué le enseñó la hormiga?", op: ["A trabajar", "A cantar", "A bailar"], correcta: "A trabajar" },
|
||||
]
|
||||
|
||||
for (const p of preguntas) {
|
||||
exercises.push({
|
||||
id: `fra9-cuento-p${idx}`,
|
||||
stage: 9,
|
||||
skillCode: `cuento-pregunta-${idx}`,
|
||||
type: "lectura",
|
||||
prerequisites: [exercises[idx - 1].id],
|
||||
content: {
|
||||
instruction: `Sobre "${cuento.titulo}":`,
|
||||
text: p.q,
|
||||
audioText: p.q,
|
||||
emoji: cuento.emoji,
|
||||
options: p.op.map((o) => ({
|
||||
label: o,
|
||||
correct: o === p.correcta,
|
||||
id: o.toLowerCase().slice(0, 12),
|
||||
})),
|
||||
},
|
||||
functionalContext: "Comprensión de cuentos clásicos: responder preguntas sobre la trama.",
|
||||
errorType: "omision-letra",
|
||||
})
|
||||
idx++
|
||||
}
|
||||
}
|
||||
|
||||
const stage: Stage = {
|
||||
id: 9,
|
||||
name: "Secuencia narrativa",
|
||||
description: "Ordenar eventos de cuentos clásicos y responder preguntas de comprensión.",
|
||||
exercises,
|
||||
}
|
||||
|
||||
export default stage
|
||||
Reference in New Issue
Block a user