Skip to content

Conversation

@hermannakos
Copy link
Collaborator

Summary

Fixes critical bug where student file submissions appeared in Canvas Submissions folder but not in SpeedGrader. This occurred when files uploaded successfully but the final submission API call failed silently due to network issues.

Changes

Database Layer (Phase 1)

  • Add SubmissionState enum with 7 states tracking submission lifecycle: QUEUED, UPLOADING_FILES, SUBMITTING, VERIFYING, COMPLETED, FAILED, RETRYING
  • Add 5 new tracking columns to CreateSubmissionEntity:
    • submission_state (tracks current state)
    • state_updated_at (timestamp)
    • retry_count (attempt counter)
    • last_error_message (error details)
    • canvas_submission_id (Canvas ID after success)
  • Create backward-compatible database migration (v6 → v7)
  • Add DAO methods: updateSubmissionState(), incrementRetryCount(), setCanvasSubmissionId(), findSubmissionsByState()

Worker & Error Handling (Phase 2)

  • Add exponential backoff policy to WorkManager (30s initial delay, exponential growth)
  • Implement intelligent retry logic in SubmissionWorker:
    • Network 5xx errors → retry up to 3 times
    • Connectivity issues → retry
    • Exceptions → retry
    • Authorization 4xx errors → permanent failure
  • Update submission states throughout upload lifecycle
  • Store Canvas submission ID and error messages

UI Foundation (Phase 3)

  • Update BaseSubmissionHelper methods to return submission IDs instead of Unit
  • Enable future UI tracking of submission progress
  • All changes backward compatible with existing UI

Test Plan

Manual Testing

  1. Enable airplane mode or use network throttling
  2. Create an assignment requiring file submission
  3. As a student, upload files to the assignment
  4. Observe files upload successfully
  5. While "Submitting" notification shows, disconnect network
  6. Verify WorkManager automatically retries submission (check logs for retry attempts)
  7. Reconnect network
  8. Verify submission completes successfully and appears in both:
    • Student's Submissions folder in Canvas
    • Teacher's SpeedGrader

Database Migration Testing

  1. Install previous version of app with existing submissions
  2. Install this build
  3. Verify database migrates successfully (v6 → v7)
  4. Verify existing submissions still work
  5. Create new submission and verify new fields populated

Edge Cases

  1. Test with process death during upload (force stop app)
  2. Test with app backgrounded during submission
  3. Verify submissions persist and resume correctly
  4. Test permanent failures (invalid auth) don't retry indefinitely

refs: MBL-19546
affects: Student
release note: Fixed issue where file submissions occasionally didn't appear in SpeedGrader after successful upload

  • Dark/light mode testing - N/A (no UI changes)
  • Landscape/tablet testing - N/A (no UI changes)
  • Accessibility testing - N/A (no UI changes)
  • Product approval - Bug fix, no product changes

🤖 Generated with Claude Code

hermannakos and others added 3 commits November 25, 2025 14:37
Implements Phase 1 and initial Phase 2 of submission bug fix:

Database Changes (Phase 1):
- Add SubmissionState enum with 7 states tracking submission lifecycle
  (QUEUED, UPLOADING_FILES, SUBMITTING, VERIFYING, COMPLETED, FAILED, RETRYING)
- Add 5 new columns to CreateSubmissionEntity for state tracking:
  - submission_state (default: QUEUED)
  - state_updated_at (nullable timestamp)
  - retry_count (default: 0)
  - last_error_message (nullable error details)
  - canvas_submission_id (nullable submission ID from Canvas)
- Create backward-compatible database migration (v6 → v7)
- Add DAO methods for state management (updateSubmissionState,
  incrementRetryCount, setCanvasSubmissionId, findSubmissionsByState)

Worker Changes (Phase 2 - Partial):
- Update SubmissionWorker to track state transitions
- Set UPLOADING_FILES state when uploading files
- Set SUBMITTING state when making submission API calls
- Import SubmissionState enum for type-safe state management

All changes are backward compatible with existing submissions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Implements remaining Phase 2 changes:

SubmissionHelper Changes:
- Add exponential backoff policy (30s initial delay)
- Configure WorkManager to retry with increasing delays
  (30s → 60s → 120s for transient failures)

SubmissionWorker Error Handling:
- Implement intelligent retry logic in handleSubmissionResult
- Distinguish between transient errors (retry) and permanent errors (fail):
  * Network 5xx errors → retry up to 3 times
  * Network errors with no code (connectivity issues) → retry
  * Exceptions → retry
  * Authorization 4xx errors → permanent failure
- Update submission state to RETRYING for retryable errors
- Update submission state to FAILED after max retries
- Track Canvas submission ID on success
- Increment retry count and store error messages in database

State Management:
- Set COMPLETED state on successful submission
- Store canvas_submission_id for verification
- Set RETRYING state for transient failures
- Set FAILED state for permanent failures or max retries exceeded

This fixes the core bug where transient network failures would lose
submissions. WorkManager will now automatically retry failed submissions
with exponential backoff, ensuring files uploaded to Canvas are properly
submitted even if the final API call initially fails.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Phase 3 changes - enable UI tracking of submission progress:

BaseSubmissionHelper Changes:
- Update all submission methods to return Long instead of Unit:
  * startTextSubmission() → returns submission ID
  * startUrlSubmission() → returns submission ID
  * startFileSubmission() → returns submission ID (or -1 if empty)
  * startMediaSubmission() → returns submission ID
  * startStudioSubmission() → returns submission ID
  * startStudentAnnotationSubmission() → returns submission ID

This enables the UI layer to:
- Track specific submission by ID
- Monitor submission state in real-time
- Show progress without closing submission view prematurely
- Navigate to upload status screen instead of immediate dismissal

The returned ID is the actual auto-generated primary key from
CreateSubmissionEntity, not the SQLite ROWID. The code correctly
uses findSubmissionByRowId() to fetch the entity and extract its ID.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@github-actions
Copy link

github-actions bot commented Nov 26, 2025

Teacher Install Page

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

Student Install Page

Copy link
Contributor

@kdeakinstructure kdeakinstructure left a comment

Choose a reason for hiding this comment

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

QA 👍

Update test mock to return Long instead of Unit to match the updated
BaseSubmissionHelper method signature.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@github-actions
Copy link

github-actions bot commented Nov 27, 2025

📊 Code Coverage Report

⚠️ Student

  • PR Coverage: 42.77%
  • Master Coverage: 42.80%
  • Delta: -0.03%

✅ Teacher

  • PR Coverage: 25.45%
  • Master Coverage: 25.45%
  • Delta: +0.00%

⚠️ Pandautils

  • PR Coverage: 22.56%
  • Master Coverage: 22.65%
  • Delta: -0.09%

📈 Overall Average

  • PR Coverage: 30.26%
  • Master Coverage: 30.30%
  • Delta: -0.04%

hermannakos and others added 2 commits November 27, 2025 14:09
…handling

- Add lastSubmissionId property to track database entity ID
- Add isFailed property to track submission failure state
- Add ensureSubmissionStateIsCurrent method to sync submission state
- Update grade cell to reflect uploading and failed states
- Fix routing to use submission entity ID instead of assignment ID
- Add updateGradeCell callback to refresh grade cell on failure
- Update all tests to include new properties
- Add testUpdateSubmissionState to CreateSubmissionDaoTest

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@github-actions
Copy link

🧪 Unit Test Results

✅ 📱 Student App

  • Tests: 1226 total, 0 failed, 0 skipped
  • Duration: 0.000s
  • Success Rate: 100%

✅ 📱 Teacher App

  • Tests: 364 total, 0 failed, 0 skipped
  • Duration: 38.110s
  • Success Rate: 100%

✅ 🌅 Horizon

  • Tests: 449 total, 0 failed, 0 skipped
  • Duration: 28.106s
  • Success Rate: 100%

✅ 📦 Submodules

  • Tests: 2418 total, 0 failed, 0 skipped
  • Duration: 54.939s
  • Success Rate: 100%

📊 Summary

  • Total Tests: 4457
  • Failed: 0
  • Skipped: 0
  • Status: ✅ All tests passed!

Last updated: Fri, 28 Nov 2025 13:07:17 GMT

Copy link
Contributor

@kristofnemere kristofnemere left a comment

Choose a reason for hiding this comment

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

QA+1

@hermannakos hermannakos merged commit 27681d1 into master Nov 28, 2025
48 of 49 checks passed
@hermannakos hermannakos deleted the MBL-19546-missing-submissions branch November 28, 2025 13:53
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.

4 participants