Repository navigation
fix(quiz): prevent fresh attempts during uncertain-start recovery - #81
Conversation
Require continuation after an unverified start even when the attempt ID was never received. Preserve the checkpoint when no continuation exists and explain recovery without inviting another graded attempt. Add complete learner CLI workflow and partial-save recovery coverage, plus an agent guide. Include CodeRabbit's account-check ordering correction in verification, covered by a regression test.
|
ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing |
[Medium impact] The PR appears safe to merge. SummaryPrevents recovery from an uncertain quiz start from creating another graded attempt, even when the attempt ID was lost.
Acknowledged context:
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Uncertain-start recovery is now continue-only —
LearnerWorkflow.starttreats anuncertain/startcursor with unknown attempt ID ascontinue_only, refusing with the new_START_NO_IDmessage (before the checkpoint rewrite) when Brightspace offers no Continue, instead of silently creating another graded attempt. verifychecks the signed-in account first — the whoami/actor check now precedes the unknown-ID refusal, which itself replaces the old_REOPENguidance on this path (_REOPENremains correctly in use in_openfor uncertainnext/previous).- Regression + workflow tests — refusal with byte-identical checkpoint (and idempotency), continuation kwargs (
continue_only=True,known_tab_id=""), verify ordering under both actor states, deliberate fresh start afterforget, plus a full CLI-loop test and a partial-save failure/recovery test driving real workflow code over synthetic responses. - Docs and baseline — new
docs/agent-quizzes.mdagent playbook (spot-checked claims against the code:--dry-runlocality, timer keys,opens_atrefusal keys, recovery table), README cross-link, and the.secrets.baselineline-number move matching the README's +6 lines.
I traced every cursor-state branch (active, submitted, uncertain with known ID, absent/invalid, cross-account) and found no behavior change beyond the intended one; the unknown-ID cursor always carries timer: None, so skipping the _time_up gate for it is sound. Adopting whatever attempt Continue offers is the right call given identity comparison is impossible. Verified locally: the changed-file tests, the learner transport suite, and the CLI workflow suite all pass; ruff check, strict mypy (only the known environmental playwright stub errors), and the rejecting secret scan are clean.
glm-5.3 | 𝕏

Summary
If Brightspace accepted a quiz start but the CLI lost the reply before receiving its attempt ID, retrying could create another graded attempt once Continue was no longer offered. Recovery now only continues an existing attempt; otherwise it stops before rewriting the encrypted checkpoint.
Changes
Validation
Local review
2 passes: the initial review round (4 seats: CodeRabbit, two correctness models and an additional security model), followed by one final pre-merge review seat.
Grok 4.7 — xhigh: SHIP (initial patch, local snapshot a03e81e7ebbf6546ea5e575ee9cc64e602b8bfbd).
GLM 5.3 — max: SHIP (final patch).
Muse Spark 1.3 contributor — xhigh: SHIP (final patch, security seat).
CodeRabbit — CLI: one minor finding, fixed in 23e9671: check actor identity before giving unknown-ID recovery advice. The fix has a failing-before/passing-after regression and the complete final suite is green.
Muse Wonder Full 1.0 — xhigh: SHIP, no actionable findings in the final pre-merge pass on 23e9671. Read-only review; no tests were run by this reviewer.
The final patch reviewed by GLM and Muse matches published head 23e9671. There are no unresolved local findings. Unsupported question types and required browser steps remain documented limitations.
Reviewer checklist