B2C Practice Player (real PYQs, structured sessions)¶
Status: Building (v1)
Owner: Bhanu
Surfaces: apps/web (new PracticeSession page, Study Plan CTA rewire), apps/backend (exam question store, practice sessions + attempts)
Why this exists (Product Mindset Gate)¶
- Who asked for it? Bhanu (owner), from dogfooding the Study Plan practice flow, with explicit competitor reference (Brilliant, Sololearn). Self-initiated hypothesis; no user interview or ticket behind it, and we say so.
- What user pain? A learner taps "Start practice" on a ranked chapter and lands in a chatbot streaming generated questions as chat bubbles. Ten questions means scrolling a conversation: no one-question-at-a-time focus, no instant right/wrong, no session progress, free-text answers. Every serious exam-prep product (Brilliant, Sololearn, Embibe, Physics Wallah, Allen) drills through a structured player, none through chat.
- Cost of NOT doing it? (a) Daily-repeat retention: nobody drills 20 chapters in chat form, and practice is the loop Pro sells. (b) M2 is blocked: the mastery write-path needs clean per-question attempt events (chapter, correct/incorrect, timestamp). Chat free-text cannot produce that reliably, so
accuracyPctstays null and the Study Plan never personalizes. - Validated or a guess? Guess, competitor-pattern informed. 7 B2C users in prod, no local usage data. Strong prior, honestly unvalidated.
- How we know it worked? Session completion rate (started -> finished), practice sessions per learner per week, next-day repeat rate. Sean Ellis counterfactual: swap the player back to chat a week after shipping; active learners would complain "where's the quiz mode".
Decisions (made with owner, 2026-07-02)¶
- Question source: real PYQs via ETL. The
knowledge_base_statusbank (6,493 questions, 1:1 answers + explanations, 100% chapter/topic-tagged, complexity-tagged) is copied into the app DB by an ETL script. The player serves real past-exam questions: instant, deterministic, no hallucinated answer keys, and each question can carry its "JEE 2018" provenance badge. - Player replaces chat practice. "Start practice" (Study Plan today card, chapter rows, and the B2C practice intent tile) opens the player. Chat remains for get_help / understand / revise.
What v1 is¶
PracticeSessionpage: one question at a time, options as tappable cards, instant correct/incorrect on submit, explanation reveal, progress ("3 of 10"), session summary (score, per-question review, back to plan).- Backend:
exam_questionsstore (ETL-fed),practice_sessions+practice_attemptstables, endpoints to start a session, submit an attempt (server grades; correct answer never ships in the session payload), and read a summary. - Session composition: 10 questions, chapter-scoped, mixed complexity (cold-start rule from the strategic-practice doc), text-only questions (figures excluded in v1).
- Attempts are persisted. This table is the substrate M2's interaction counters read from.
- "Ask AI" on the feedback state: deep-links into the get_help chat with the question, the learner's answer, and the correct answer pre-seeded (uses the existing location.state seed handshake).
Non-goals (v1)¶
- Figure/diagram questions (
has_figure, 1,107 of 6,493) — needs asset serving; v1 filters them out. - Adaptive within-session difficulty (v1 fixes the set at start; adaptivity comes with M2 mastery).
- LLM top-up for chapters with thin PYQ coverage (hybrid mode was considered, deferred; thin chapters just get shorter sets).
- Timed/exam-mode sessions, mixed-chapter mock tests, spaced-repetition scheduling (
due_revisionsstill 0). - Trainer-authored practice paths (B2B homework/mock-test flows untouched).
Rejected alternatives¶
- LLM-generated questions in a player shell (fastest ship): rejected. Latency per set, answer-key hallucination risk, no provenance, and attempts against generated questions are weaker mastery evidence than attempts against tagged PYQs.
- Keep chat as a second practice entry point: rejected. Two competing practice surfaces split the funnel metric the Gate defines and confuse "where do I practice".
- Serving questions live from
knowledge_base_status: rejected. The request path stays inside the app DB (same rule as the Study Plan engine); the bank DB is a pipeline artifact, not a serving store.
How it works¶
Study Plan CTA ──► /practice/session?subject=X&chapter=Y
│ POST /api/v1/practice-sessions
▼
picks 10 text-only questions for chapter (complexity mix)
│ learner answers one by one
▼
POST /practice-sessions/{id}/attempts (server grades)
│ correct? + explanation back per question
▼
summary screen ──► back to Study Plan
(attempts persisted ──► M2 interaction counters)
ETL: scripts/etl_exam_questions.py reads the bank DB (read-only DSN via env) and upserts into exam_questions. Run per environment; the bank stays the source of truth until the ingestion repo owns this.
Changelog¶
- 2026-07-02 — doc created alongside v1 implementation (same PR).
- 2026-07-02 — "Ask AI" promoted from non-goal to v1 after owner dogfood (chat felt missing from the drill); KaTeX rendering added for questions/options/explanations (bank content is LaTeX-heavy).