feat(07): Spaced repetition study system (SM-2) - #49
Open
tpaulshippy wants to merge 9 commits into
Open
Conversation
…endpoints, deck annotations
Implements docs/roadmap/07-spaced-repetition-study.md backend sections:
- Flashcard scheduling fields (due_at, interval_days, ease, reps, lapses,
last_reviewed_at) with due_at=now default so new cards are studyable
immediately, including agent-created ones
- Pure apply_sm2(card, rating, now) in bots/services/srs.py (Again/Hard/
Good/Easy), unit-tested and swappable; no math in the viewset
- POST /api/decks/{deck_id}/flashcards/{id}/review/ reschedules via srs.py
and writes a FlashcardReview log row
- GET /api/decks/{deck_id}/study_queue/?mode=due|all&limit=N ordered by
due_at asc (nulls last)
- Deck list/detail serializers gain due_count + last_studied_at annotations
- FlashcardViewSet now scopes lookups to the requesting user's decks and
requires IsAuthenticated, so foreign decks 404 like every other resource
- seed_e2e_spaced_repetition management command (idempotent) for Detox runs
…ngs, due badges
Implements docs/roadmap/07-spaced-repetition-study.md frontend sections:
- flashcards/study.tsx: study queue via GET study_queue?mode=due with
'Study all anyway' fallback, rotateY flip animation, rating row
(Again/Hard/Good/Easy with interval hints) revealed after the flip,
review POST per rating, haptics (warning on Again, light on others),
session summary (reviewed count, Again count, 'Next due in X'), testIDs
on all new interactive elements
- flashcards.tsx list rows: red 'N due' badge + 'Last studied X ago' line
- flashcards/deck.tsx: Study button label 'Study (N)' from deck.due_count,
passes mode=due; study-button testID
- api/flashcards.ts: scheduling field types, fetchStudyQueue,
reviewFlashcard
- drawer/menu button testIDs for e2e navigation
- typecheck fixes for pre-existing errors in __mocks__/handlers.ts and
__tests__/api/{apiClient,bots,profiles,aiModels}.test.ts so tsc is clean;
new fetchStudyQueue/reviewFlashcard tests in flashcards.test.ts
- package.json: run jest with --watchman=false (local watchman daemon broken)
…ngs, due badges
Implements docs/roadmap/07-spaced-repetition-study.md frontend sections:
- flashcards/study.tsx: study queue via GET study_queue?mode=due with
'Study all anyway' fallback, rotateY flip animation, rating row
(Again/Hard/Good/Easy with interval hints) revealed after the flip,
review POST per rating, haptics (warning on Again, light on others),
session summary (reviewed count, Again count, 'Next due in X'), testIDs
on all new interactive elements
- flashcards.tsx list rows: red 'N due' badge + 'Last studied X ago' line
(deck-row-* / deck-due-badge-* testIDs)
- flashcards/deck.tsx: 'Study (N)' button from deck.due_count, mode=due
param, study-button testID
- api/flashcards.ts: scheduling field types, fetchStudyQueue,
reviewFlashcard, Deck.due_count/last_studied_at
- drawer-item-flashcards + drawer-menu-button testIDs for e2e navigation
- new fetchStudyQueue/reviewFlashcard tests in flashcards.test.ts
Note: these changes were previously stashed by an external checkpoint tool
(stash@{0}, commit e64f5ad) mid-session; restored from that stash.
front/e2e/07-spaced-repetition.e2e.js models chatImageUpload.e2e.js: JWT auth against API_BASE/token/, profile/bot/deck fetched from the seed data, AsyncStorage injected via simctl, then drawer -> Flashcards -> 'Cell Bio' deck -> Study -> six cards rated Again/Hard/Good/Easy -> session-complete summary -> Done. Verifies next-due state afterwards: study_queue?mode=due returns [], the deck shows the nothing-due state with 'Study all anyway', and the list row's red due badge disappears. Header comment documents the idempotent seed_e2e_spaced_repetition management command and env vars. back-button testID added to shared BackButton for navigation.
added 3 commits
August 26, 2026 03:56
- Backend: remove unused studied variable, fix import ordering - Frontend: replace useRef with useState for Animated.Value and Date.now() - Frontend: add jest globals to eslint config
tpaulshippy
pushed a commit
that referenced
this pull request
Aug 26, 2026
Screenshot shows the flashcards deck list with Biology 101 (12 cards) and World History (8 cards).
Screenshot shows the flashcards deck list with Biology 101 (12 cards) and World History (8 cards).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Roadmap 07: Spaced Repetition Study
Implements #59.
What changed
srs.py),due_at/interval/ease/reps/lapses fields on Flashcard,FlashcardReviewlog model,POST .../review/endpoint,GET .../study_queue/with due filtering, deck annotations (due_count, last_studied_at)<1d/1d/3d/7dhints, progress tracking, completion summary, due badges on deck listDemo
manage.py seed_e2e_spaced_repetition→ 8 Cell Bio cards (6 due)Evidence
https://github.com/tpaulshippy/bots/raw/feature/roadmap-07-spaced-repetition/evidence/pr49-spaced.mp4