fix: a skipped question is not a wrong answer
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
This commit is contained in:
parent
0e6c18d886
commit
5add9f23dd
3 changed files with 10 additions and 4 deletions
|
|
@ -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.",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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' },
|
||||
|
|
|
|||
|
|
@ -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() {
|
|||
|
||||
<InProgressQuizzes />
|
||||
|
||||
<CategoryPerformance />
|
||||
|
||||
<MyNote variant="card" />
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue