Skip to content

Prevent duplicate test submissions. - #3257

Open
drgrice1 wants to merge 1 commit into
openwebwork:developfrom
drgrice1:test-resubmit-protect
Open

drgrice1 wants to merge 1 commit into
openwebwork:developfrom
drgrice1:test-resubmit-protect

Conversation

@drgrice1

Copy link
Copy Markdown
Member

If a test submission is slow (for example on a bad connection), then the student can submit the test again while the first submission is still being graded. Since the number of attempts is not saved until grading is complete, both submissions were graded as the same attempt, and the one that finished last overwrote the scores of the other. This happened even for tests that allow only one submission per version.

The gateway form now only allows one submission. On the server, the version_last_attempt_time and number of attempts used when the page was rendered are included in the form. A submission is not graded if the number of attempts has changed. Otherwise the submission time is saved with a conditional database update that only succeeds if version_last_attempt_time is unchanged (the new value is always later than the old one, so that two submissions can not both succeed). The proctor login page saves the time in the same way and forwards the new value. Finally, before any scores are saved, the new number of attempts for one problem is saved with a conditional database update that only succeeds if that number is unchanged. That catches a submission from a page rendered while another submission was being graded.

To reproduce the issues, make a test with the following problem and at least one other problem, set "Graded submissions per version" to 1 (except as noted), and assign it to a student. Grading the problem takes 10 seconds, which leaves time to submit again during grading.

DOCUMENT();
loadMacros('PGstandard.pl', 'PGML.pl');

if ($inputs_ref->{submitAnswers}) {
    my $start = time;
    1 while time - $start < 10;
}

BEGIN_PGML
What is [`1 + 1`]? [_]{2}
END_PGML
ENDDOCUMENT();

In each case below, before this change both submissions are recorded and the last to finish overwrites the scores of the other. With this change only the first submission is recorded.

  1. Answer all problems, click "Grade Test" and "Yes", and then click "Grade Test" again within 10 seconds.

  2. Set the test to show one problem per page. Answer the first problem, click "Next Problem", answer the second problem, and click "Grade Test" on that page. Within 10 seconds, click the back button and click "Grade Test" again. The page that the back button returns to does not have the answer to the second problem, so before this change that answer is lost and the problem is scored as unanswered (the answer log shows both submissions). Grading an older copy of the test that is open in another tab is the same.

  3. Answer all problems, grade the test, reload the page (F5) within 10 seconds, change an answer, and grade the test again.

  4. With "Graded submissions per version" set to 2, repeat 2 but wait for the results before clicking the back button. Before this change, the submission from the old page is graded as the second attempt. With this change it is not graded.

  5. Change the test to a proctored test that requires proctor authorization to grade, and repeat 1 and 2, authorizing each submission with a proctor account. Also click the proctor login button twice for one submission. Only one submission is graded.

Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

@drgrice1
drgrice1 force-pushed the test-resubmit-protect branch from 1cc284f to d8c2701 Compare October 27, 2026 21:09
If a test submission is slow (for example on a bad connection), then the
student can submit the test again while the first submission is still
being graded.  Since the number of attempts is not saved until grading is
complete, both submissions were graded as the same attempt, and the one
that finished last overwrote the scores of the other.  This happened even
for tests that allow only one submission per version.

The gateway form now only allows one submission.  On the server, the
version_last_attempt_time and number of attempts used when the page was
rendered are included in the form.  A submission is not graded if the
number of attempts has changed.  Otherwise the submission time is saved
with a conditional database update that only succeeds if
version_last_attempt_time is unchanged (the new value is always later
than the old one, so that two submissions can not both succeed).  The
proctor login page saves the time in the same way and forwards the new
value.  Finally, before any scores are saved, the new number of attempts
for one problem is saved with a conditional database update that only
succeeds if that number is unchanged.  That catches a submission from a
page rendered while another submission was being graded.

To reproduce the issues, make a test with the following problem and at
least one other problem, set "Graded submissions per version" to 1
(except as noted), and assign it to a student.  Grading the problem takes
10 seconds, which leaves time to submit again during grading.

    DOCUMENT();
    loadMacros('PGstandard.pl', 'PGML.pl');

    if ($inputs_ref->{submitAnswers}) {
        my $start = time;
        1 while time - $start < 10;
    }

    BEGIN_PGML
    What is [`1 + 1`]? [_]{2}
    END_PGML
    ENDDOCUMENT();

In each case below, before this change both submissions are recorded and
the last to finish overwrites the scores of the other.  With this change
only the first submission is recorded.

1. Answer all problems, click "Grade Test" and "Yes", and then click
   "Grade Test" again within 10 seconds.

2. Set the test to show one problem per page.  Answer the first problem,
   click "Next Problem", answer the second problem, and click "Grade
   Test" on that page.  Within 10 seconds, click the back button and
   click "Grade Test" again.  The page that the back button returns to
   does not have the answer to the second problem, so before this change
   that answer is lost and the problem is scored as unanswered (the
   answer log shows both submissions).  Grading an older copy of the test
   that is open in another tab is the same.

3. Answer all problems, grade the test, reload the page (F5) within 10
   seconds, change an answer, and grade the test again.

4. With "Graded submissions per version" set to 2, repeat 2 but wait for
   the results before clicking the back button.  Before this change, the
   submission from the old page is graded as the second attempt.  With
   this change it is not graded.

5. Change the test to a proctored test that requires proctor
   authorization to grade, and repeat 1 and 2, authorizing each
   submission with a proctor account.  Also click the proctor login
   button twice for one submission.  Only one submission is graded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@drgrice1
drgrice1 force-pushed the test-resubmit-protect branch from d8c2701 to a3e2392 Compare October 30, 2026 20:38
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