Mark a practice session as completed and return the score
POST/sessions/:session_id/complete
Sets the session's completed_at = now() and returns the
finalized session payload with a server-computed
score_percentage. Can be called even when not all questions
were answered (the user quit early) -- total_questions
stays at the snapshot value, correct_answers reflects
only the answers actually submitted.
Score: round((correct_answers / total_questions) * 100),
rounded to the nearest integer. When total_questions is 0
(theoretically unreachable -- create-quiz requires >=1 --
but the read-side defensively handles it), the score is 0
rather than a division-by-zero panic.
Authorization: the session must belong to the authenticated user (403 otherwise). Once completed, a second call returns 409 -- this endpoint is NOT idempotent. Callers that want to fetch a completed session's state should use GET /api/sessions/{id} (ASK-152, future).
Race protection: SELECT FOR UPDATE on the session row serializes against any concurrent SubmitAnswer (ASK-137). If an answer commits first, it's counted in the final score; if complete commits first, the answer call returns 409.
Response shape: similar to PracticeSessionResponse but
without the answers array (callers can fetch them via
GET /api/sessions/{id}) and with the new
score_percentage field. completed_at is non-nullable
on this endpoint -- a successful response always carries
the freshly-set timestamp.
Request
Responses
- 200
- 400
- 401
- 403
- 404
- 409
- 500
Session completed; returns the final state with score.
Bad request
Unauthorized
Forbidden
Not found
Conflict with current resource state
Internal server error