Skip to content

feat: deduplicate markLessonComplete with 500ms guard window#746

Merged
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
mrteeednut007-dotcom:feat/deduplicate-mark-lesson-complete
Jun 30, 2026
Merged

feat: deduplicate markLessonComplete with 500ms guard window#746
RUKAYAT-CODER merged 1 commit into
rinafcode:mainfrom
mrteeednut007-dotcom:feat/deduplicate-mark-lesson-complete

Conversation

@mrteeednut007-dotcom

Copy link
Copy Markdown
Contributor

Deduplicate markLessonComplete with 500 ms guard window

Problem

In the video player, lesson completion fires from two sources — video end and manual skip. When
both triggers fire within milliseconds of each other (e.g. a user skips a short lesson right as
it ends), markLessonComplete was called twice in rapid succession. This caused:

  • Duplicate completion records written to the server
  • overallProgress double-incrementing
  • Potential false course-completion events

Solution

Added a module-level completionInProgress Set that acts as a per-lesson deduplication guard:

  • On the first call for a given courseId:lessonId key, the optimistic state update fires
    normally and the key is added to the set
  • Any subsequent call within 500 ms hits the guard and returns early — no state mutation, no
    API call
  • After 500 ms the key is removed, so a genuine retry or re-completion works as expected
  • Guard is scoped to courseId:lessonId so different lessons and different courses are never
    blocked by each other

Changes

  • src/store/courseProgressStore.ts — added completionInProgress Set, _completionTimers Map, and
    guard logic at the top of markLessonComplete
  • src/tests/store/courseProgressStore.test.ts — 6 new tests covering all acceptance
    criteria

Tests

All 11 tests pass (npm test):

┌──────────────────────────────────────┬────────┐
│ Test │ Covers │
├────────────────────────────────────────────────┼─────────────────────────────┤
│ Second call within 500 ms is ignored │ AC1 — single state mutation │
├────────────────────────────────────────────────┼─────────────────────────────┤
│ Two rapid calls → 1 mutation (state assertion) │ AC1 — no double update │
├────────────────────────────────────────────────┼─────────────────────────────┤
│ Call after 500 ms proceeds normally │ AC2 — third call works │
├────────────────────────────────────────────────┼─────────────────────────────┤
│ overallProgress increments exactly once │ AC3 — no double increment │
├────────────────────────────────────────────────┼─────────────────────────────┤
│ Guard is per lessonId │ Isolation │
├────────────────────────────────────────────────┼─────────────────────────────┤
│ Guard is per courseId │ Isolation │
└────────────────────────────────────────────────┴─────────────────────────────┘

close #628

- Add module-level completionInProgress Set to block duplicate calls
  within a 500ms window (e.g. video-end + manual skip firing together)
- Optimistic state update fires on first call; subsequent calls within
  the window return early without mutating state or triggering an API call
- Add _completionTimers Map (exported) for clean timer teardown in tests
- Add 6 unit tests covering all acceptance criteria:
  - Two rapid calls result in a single state mutation
  - Guard clears after 500ms so a third call succeeds normally
  - overallProgress increments exactly once per burst
  - Guard is scoped per lessonId and per courseId independently

Fixes duplicate completion records and double-incremented progress
counters when multiple triggers fire for the same lesson.
@drips-wave

drips-wave Bot commented Jun 30, 2026

Copy link
Copy Markdown

@mrteeednut007-dotcom Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Thank you for contributing to the project.

@RUKAYAT-CODER RUKAYAT-CODER merged commit f4969ae into rinafcode:main Jun 30, 2026
2 of 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.

[Bug] courseProgressStore lesson completion not debounced — rapid lesson skips create duplicate completions

2 participants