An unsuspended exam keeps running. When its clock runs out it is
submitted with what was answered and the score counts — a learner who
ran out of time sat an exam, which is a result and not an accident to
hide. Previously it was graded, flagged expired=1, excluded from every
statistic, and the client was told the opposite ("submit manually").
- attempt_expiry.settle_if_expired: one path, used by resume and by the
sessions list, so an exam left open elsewhere shows its score rather
than "in progress" forever. Suspended attempts hold their clock and
never expire.
- resume returns {expired_submitted, attempt_id}; the client opens the
analysis. The suspend dialog and the leave warning now say what
actually happens.
- delete: saved progress and device lock cleared; a study-plan block
whose only completed attempt is deleted goes back to unfinished.
- POST /attempts/reset-all: typed RESET, removes attempts, answers,
in-progress state, plan progress, reading marks, saved questions and
question notes; leaves the account, authored content and AI chats.
Settings → Your data, with the counts reported afterwards.
Also fixed on the way: the first version of the sessions-list change
mutated the dict it was iterating; the test only passed because it had
one attempt. Now two.
Backend 223/223, frontend 258/258.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN