Living Word Classroom Reporting — Teacher View (Phase D-3)
STATUS: SHIPPED 2026-06-04 (PR #740). Founder resolved R1–R4: R1=performance, R2=instrument, R3=AGGREGATE-only (no per-child scores), R4=AI-Bridge framing. Implemented:
lw_classroom_student_activitytable (completion events),POST /classrooms/activity(device-cookie, no-op if not joined), in-game fire-and-forgetuseEffecton enemy defeat, owner-scopedGET /classrooms/[id]/report(aggregate), and theClassroomReportSectionon the manage page. Instrumentation chain preview-verified; report UI is on the auth-gated page (founder manual confirm).
§0 — The load-bearing finding (verified 2026-06-04)
The deep-dive roadmap calls the teacher reporting view "cheap / high-value — the quiz-attempt data is already written and never surfaced, mostly a read on existing data." That is not true for classroom students. Verified against the live DB:
game_quiz_attempts.user_idis NOT NULL → attempts are recorded only for authenticated users (cloud-save accounts). There is nodevice_idand noclassroom_idcolumn.lw_classroom_studentsrows are anonymous + device-based (founder-locked D2: first name only, no email, no password, per-device cookie). A classroom student has noauth.usersrow, so they generate zerogame_quiz_attemptsrows.
Therefore: for the typical classroom (kids who joined with a code + nickname, never signed in), there is no per-student quiz-performance data in existence to "read." A meaningful performance report requires new instrumentation, not a read.
§1 — What we CAN report today with zero new instrumentation
From lw_classroom_students + lw_classroom_events (already built, Phase D):
- Roster: nickname, joined date.
last_played_at(column exists onlw_classroom_students— but NOTE: verify whether anything currently WRITES it; if nothing updates it on play, it is always null and must be wired).- Join funnel: counts of
student_joined, failed-join attempts, code rotations (lw_classroom_events).
That is an engagement/roster report, not a learning/performance report. It answers "who joined and when," not "how is each student doing on the quizzes."
§2 — The decisions (founder)
| # | Decision | Options |
|---|---|---|
| R1 | Scope of v1 reporting. | (a) Engagement-only (roster + joined/last-played + join funnel) — buildable now, no new writes, but no quiz performance. (b) Performance (per-student/score/topic mastery) — requires R2. |
| R2 | Instrument anonymous-student activity? Performance reporting needs a new device-keyed write path: a lw_classroom_student_activity table (FK → lw_classroom_students) written when a joined device completes a quiz, capturing score/percentage/scene/difficulty/timestamp. This is genuinely new code in the game's quiz-completion flow, gated on "this device is in a classroom." | (a) Yes, instrument. (b) No — keep engagement-only until demand proven. |
| R3 | Minors' performance data — privacy posture. Even anonymous (nickname-only), per-student score data about children is sensitive. | (a) Aggregate-only to the teacher (class averages, topic gaps — no per-child scores). (b) Per-student scores visible to the owning teacher only (RBAC: owner_user_id = auth.uid()), never exported, never to other students. (c) Per-student + printable/exportable. |
| R4 | AI-Bridge framing. Reporting must not become a surveillance or judgment surface. | Confirm copy frames it as "where your class needs a hand," points teachers to teach the gap (bridge to the human teacher), never ranks/shames a child. |
§3 — Proposed v1 (pending R1–R4), illustrative only
If R1=engagement-only: a "Class activity" section on /living-word/classrooms/[id] — roster with joined/last-played, a small join-funnel summary. Read-only over existing tables. ~half a day. (Requires wiring last_played_at updates if not already written.)
If R1=performance + R2=instrument + R3=aggregate: add lw_classroom_student_activity (migration, founder-gated apply), write to it from the quiz-completion path when the device is classroom-joined, then a reporting section showing class-level mastery by scene/topic + per-student last-played (no per-child score list under R3a). Multi-PR: instrument → migration → reporting UI. ~2–4 days.
§4 — PASS/FAIL (to be completed once R1–R4 are set)
TBD after decisions. At minimum: owner-scoped (a teacher sees only their own classes — 404 otherwise); no minor PII beyond nickname; AI-Bridge copy reviewed; deployed-preview verification of the report rendering with seeded data.
§5 — Recommendation
Start with R1=(a) engagement-only for v1 (real value: "did my students actually join and play?", buildable now over existing data, zero new minor-data collection), and treat performance reporting as its own later sub-phase once a teacher actually asks for it — at which point R2/R3 get decided with that real demand in view. This avoids instrumenting children's score data speculatively.