Skip to content

fix(quiz): prevent fresh attempts during uncertain-start recovery - #81

Merged
rabesss merged 1 commit into
mainfrom
fix/quiz-uncertain-start-recovery
Nov 1, 2026
Merged

rabesss merged 1 commit into
mainfrom
fix/quiz-uncertain-start-recovery

Conversation

@rabesss

@rabesss rabesss commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

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

  • Require continuation after every uncertain start, including when the attempt ID is unknown, while preserving known-attempt identity checks.
  • Check the signed-in account before returning unknown-ID verification guidance.
  • Add regression tests for refusal, checkpoint preservation, continuation, account mismatch and deliberate fresh start after forget.
  • Add a complete learner CLI workflow test and a partial-autosave failure/recovery test using synthetic client responses and real workflow/parsing code.
  • Document an agent's discovery, opening-time, answer, submit and recovery loop. Move one existing audited README baseline entry's line number; its hash and classification are unchanged.

Validation

  • 2,977 tests passed, with 91% combined coverage. Final files were checked in four disjoint pytest batches because pytest-xdist is absent from the local environment; no dependencies were installed.
  • Ruff, strict mypy (40 source files), import contracts, deptry, xenon, rejecting secret scan (including new files), and git diff --check passed.
  • New recovery regressions failed before the fixes and passed afterward.
  • No live LMS attempt or real credential/capture data was used.
  • All required CI checks and non-skipped hosted checks passed on 23e9671 before merge. Hosted reviews reported no actionable findings; these results are separate from the local evidence below.

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

  • Full local test suite passes.
  • Ruff and strict mypy are clean.
  • JSON-only stdout contract preserved; prompts and diagnostics stay on stderr.
  • No real credentials, cookies, TOTP codes or SAML tokens added to code, output or tests.
  • MFA semantics unchanged.
  • Behavior changes have tests.
  • Dependencies unchanged.

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-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@factory-droid

factory-droid Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Droid finished @rabesss's task —— View job


The candidate list is empty, so there are no review comments to approve or reject. Read the complete PR diff and existing comments; validation was static, and tests were not run.

0 inline comments posted

@greptile-apps

greptile-apps Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge.

Summary

Prevents recovery from an uncertain quiz start from creating another graded attempt, even when the attempt ID was lost.

  • An uncertain quiz start can no longer quietly begin another graded attempt.
  • Agents now have one guide for the learner quiz workflow.

Acknowledged context:

  • rabesss describes unsupported question types and required browser steps as intentional limitations.
  • rabesss states that the earlier finding about unknown-ID guidance appearing before account checks was fixed. The changed guard order and regression test confirm the fix.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Recover uncertain start] --> B{Continue available?}
  B -->|No| C[Stop and preserve checkpoint]
  B -->|Yes| D[Continue existing attempt]
  D --> E{Known attempt ID?}
  E -->|Yes| F[Require matching ID]
  E -->|No| G[Save returned ID]
  F --> H[Read page and timer]
  G --> H
Loading

Reviews (1) · Last reviewed commit: "fix(quiz): prevent fresh attempts during..." · Reviewed by Greptile

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Uncertain-start recovery is now continue-only — LearnerWorkflow.start treats an uncertain/start cursor with unknown attempt ID as continue_only, refusing with the new _START_NO_ID message (before the checkpoint rewrite) when Brightspace offers no Continue, instead of silently creating another graded attempt.
  • verify checks the signed-in account first — the whoami/actor check now precedes the unknown-ID refusal, which itself replaces the old _REOPEN guidance on this path (_REOPEN remains correctly in use in _open for uncertain next/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 after forget, 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.md agent playbook (spot-checked claims against the code: --dry-run locality, timer keys, opens_at refusal keys, recovery table), README cross-link, and the .secrets.baseline line-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.

Pullfrog  | View workflow run | Using glm-5.3 | 𝕏

@rabesss
rabesss merged commit cb66fb7 into main Nov 1, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant