feat(quiz): confidence rating — pre-reveal prompt, calibration, and agent visibility - #31
Conversation
In practice mode, committing a deterministic question (mcq/tf/mermaid) now asks "How sure are you? 1–5" before revealing. After the rating, the answer reveals as before and the card surfaces calibration: - confident (≥4) but wrong → "Confident but wrong — worth a closer look." (red) - right but unsure (≤2) → "Right — but you weren't sure. Lock in why." (orange) - otherwise just shows the rating. Honor-system and client-side only (the answer already ships in /state); confidence is collected only in practice mode (exam mode keeps the batch flow untouched). Surfacing high-confidence-wrong is the calibration payoff. Frontend only. Verified in a real browser: the picker gates the reveal; rating 2 on a correct answer flags under-confidence; rating 5 on a wrong answer flags over-confidence; exam mode shows no picker. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Confidence (the 1–5 self-rating from #31's pre-reveal prompt) was browser-only; now it's persisted server-side and surfaced to the host agent, so it can act on confidence-vs-correctness — re-probe confident-but-wrong questions, drill weak concepts. - POST /confidence {question_id, value:1-5} — browser fires it on pick (validated; rejects out-of-range and non-int, incl. bool). - QuizState.confidences: dict[str,int] — persisted in the snapshot beside answers; reset on set_quiz, dropped per-question on replace_question. - QuestionResult.confidence: int | None — grade_state attaches each reader's rating to the result the `grade` tool returns. - get_answers tool now returns `confidences` too (agent can inspect before grading), with a docstring nudge to follow up on confident-but-wrong / unsure answers. - JS pick(n) mirrors the local rating to the server (fire-and-forget). Backward compatible: confidence is optional throughout; old snapshots load with an empty map and results with confidence=None. Tested: state persistence/reset/drop; QuestionResult.confidence validation; /confidence record + 422s; get_answers + grade carry confidence. Verified in a real browser: rating → POST /confidence → /state.confidences → grade result carries confidence end-to-end. Full suite green; ruff + mypy --strict clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quiz resultsTotal: 60% Question 1 — ❌ 0%Prompt: Which diagram correctly shows what Your answer: Question 2 — ✅ 100%Prompt: Before this PR, Your answer: Question 3 — ✅ 100%Prompt: A user rates confidence 4 ('Fairly sure') and their answer is correct. What does Your answer: Question 4 — ✅ 100%Prompt: In exam mode, a user who answers a question will see the confidence prompt before the result is revealed. Your answer: Question 5 — ❌ 0%Prompt: The comment on line 415 says confidence is an 'honor system (the answer's already in the page)'. What does this mean for the integrity of the calibration feedback, and why did the author still consider it worth shipping? Your answer:
Results state (used by the CLI){
"version": "1",
"pr_number": 31,
"total_score": 60,
"per_question": [
{
"question_id": "q1",
"correct": false,
"score": 0,
"feedback": "",
"confidence": 4
},
{
"question_id": "q2",
"correct": true,
"score": 100,
"feedback": "",
"confidence": 2
},
{
"question_id": "q3",
"correct": true,
"score": 100,
"feedback": "",
"confidence": 3
},
{
"question_id": "q4",
"correct": true,
"score": 100,
"feedback": "",
"confidence": 2
},
{
"question_id": "q5",
"correct": false,
"score": 0,
"feedback": "The answer (\"testing\") does not address any rubric item — it makes no claim about the answer being accessible in the page before the confidence prompt, about calibration data relying on honest self-reporting, or about why the feature is still worth shipping despite that limitation.",
"confidence": null
}
]
} |
What
Roadmap #3 — the confidence slice of the feedback loop, end to end.
In the browser (practice mode): committing a deterministic question (mcq/tf/mermaid) asks "How sure are you? 1–5" before revealing. The revealed card surfaces calibration:
Exposed to the host agent (so it can follow up — re-probe confident-but-wrong, drill weak concepts):
POST /confidence {question_id, value:1-5}— fired on pick (validated; rejects out-of-range / non-int).QuizState.confidences: dict[str,int]— persisted in the snapshot beside answers; reset onset_quiz, dropped per-question onreplace_question.QuestionResult.confidence: int | None—grade_stateattaches each rating to thegradetool result.get_answerstool returnsconfidencestoo (agent can inspect before grading), with a docstring nudge.Scope / invariants
confidence=None./state); the server copy just mirrors the local rating for the agent.Teach-back (#6) is the remaining feedback-loop slice, as its own PR.
Testing
QuestionResult.confidencevalidation (1–5);/confidencerecord + 422 paths;get_answers+gradecarry confidence. Fullmcp/enginesuite green;ruff+ruff format+mypy --strictclean.POST /confidence→/state.confidences→ grade result carriesconfidence. Screenshots shared.🤖 Generated with Claude Code