From 5add9f23ddd6ab828630c28d6f1f9ee973bd4834 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 11 Sep 2026 03:21:13 +0200 Subject: [PATCH] fix: a skipped question is not a wrong answer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Performance by category counted every row in an attempt, and an attempt holds a row for each question including the ones never answered. A 360-question sitting that was opened and abandoned therefore landed as 360 wrong answers, which is why Emergency Medicine read 0% of 400 and Gastroenterology 1.1% of 277 — figures that describe a sitting nobody worked through, not a learner who cannot do emergency medicine. Accuracy now counts only questions that were actually answered, and the note under the heading says so. Coverage is a separate question from accuracy and conflating them made both useless. Also: the category performance block is gone from the dashboard, where it duplicated the one on Analysis; and the nav says Sessions rather than Quizzes, with History beside it — "quiz" describes the packaging, a learner sits a session, and the two entries answer different questions: what can I sit, and what have I sat. 208 backend, 249 frontend green. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN --- backend/app/routers/study_tools.py | 6 +++++- frontend/src/components/Navbar.jsx | 6 +++++- frontend/src/pages/DashboardPage.jsx | 2 -- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/backend/app/routers/study_tools.py b/backend/app/routers/study_tools.py index c66c5bd..d6fe309 100644 --- a/backend/app/routers/study_tools.py +++ b/backend/app/routers/study_tools.py @@ -181,6 +181,10 @@ def performance_by_category(db: Session = Depends(get_db), user: User = Depends( Question, Question.id == AttemptAnswer.question_id).filter( QuizAttempt.user_id == user.id, QuizAttempt.completed_at.isnot(None), or_(QuizAttempt.expired == 0, QuizAttempt.expired.is_(None)), Quiz.course_id.is_(None), + # A skipped question is not a wrong answer. Counting it as one made a + # 360-question sitting that was never worked through read as 0% accuracy + # across every category it touched. + AttemptAnswer.user_answer.isnot(None), AttemptAnswer.user_answer != "", ).all() extra: dict[int, set[int]] = defaultdict(set) for qid, cid in db.query(QuestionCategoryLink.question_id, QuestionCategoryLink.category_id).all(): @@ -206,7 +210,7 @@ def performance_by_category(db: Session = Depends(get_db), user: User = Depends( return { "total_answered": sum(row["answered"] for row in categories), "categories": categories, - "basis": "Your completed, non-expired general test answers; a question counts in every category it belongs to.", + "basis": "Questions you actually answered in completed sessions; skipped ones are left out, and a question counts in every category it belongs to.", } diff --git a/frontend/src/components/Navbar.jsx b/frontend/src/components/Navbar.jsx index 33ab937..082b84a 100644 --- a/frontend/src/components/Navbar.jsx +++ b/frontend/src/components/Navbar.jsx @@ -107,7 +107,11 @@ export default function Navbar({ onSignIn, onRegister }) { { to: '/home', label: 'Home' }, { to: '/', label: 'Dashboard' }, { to: '/ai', label: 'AI Mode' }, - { to: '/quizzes', label: 'Quizzes' }, + // "Quiz" describes the packaging; a learner sits a session. Both entries + // are here because they answer different questions: what can I sit, and + // what have I sat. + { to: '/quizzes', label: 'Sessions' }, + { to: '/sessions', label: 'History' }, { to: '/analysis', label: 'Analysis' }, { to: '/question-bank', label: 'Question Bank' }, ...(canManageQuestions ? [{ to: '/questions/manage', label: 'Manage Qs' }, diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx index 44b6998..4c07cbc 100644 --- a/frontend/src/pages/DashboardPage.jsx +++ b/frontend/src/pages/DashboardPage.jsx @@ -4,7 +4,6 @@ import { Link } from 'react-router-dom' import api from '../api/client' import LineChart from '../components/LineChart' import InProgressQuizzes from '../components/InProgressQuizzes' -import CategoryPerformance from '../components/CategoryPerformance' import MyNote from '../components/MyNote' import { useAuth } from '../context/AuthContext' @@ -86,7 +85,6 @@ export default function DashboardPage() { -