Skip to content

feat(studio): experimental FSRS-4.5 scheduler for flashcards (off by default) - #20

Merged
eulogep merged 1 commit into
mainfrom
feat/fsrs-experimental
Oct 23, 2026
Merged

eulogep merged 1 commit into
mainfrom
feat/fsrs-experimental

Conversation

@eulogep

@eulogep eulogep commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Summary

Applies the recommendation from #19 without changing the default: Plan tab → Leitner (current, default) or FSRS-4.5 (experimental). FSRS rebuilds each card memory from its own review log (no new state, reversible) and schedules at 90 % predicted recall (interval = stability, 1–365 days).

Test plan

  • npm test 631/631 (5 new), typecheck, eslint ., production build
  • Browser 5/5: default Leitner, FSRS first success scheduled in 4 days, rating logged, choice persists; regression core 27/27, P2 17/17

🤖 Generated with Claude Code

…default)

Applies the recommendation from the real-log evaluation without changing
the default: the Plan tab offers Leitner (current, default) or FSRS-4.5
(experimental). FSRS rebuilds each card's memory from its own review log
(no new stored state; switching back is always possible) and schedules
the next review when predicted recall reaches 90 % (interval = stability,
1–365 days).

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

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
daily-english-mission Ready Ready Preview Oct 23, 2026 4:53am UTC

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Oct 23, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6bc39df2-52c8-48d7-b6d8-f34d0ee495ad
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T04:56:20.800794Z a6b1649 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@eulogep
eulogep merged commit c90fd3b into main Oct 23, 2026
5 checks passed
@eulogep
eulogep deleted the feat/fsrs-experimental branch October 23, 2026 04:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a6b1649f97

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

import type { AskCourseAnswer } from "../academic-workspace/types";
import { addDays, applyReview, type DayKey, type ReviewOutcome, type ReviewState } from "../daily-english/spaced-review";
import type { ReviewEvent } from "../scientific-pedagogy/replay";
import { fsrsIntervalDays, fsrsMemoryFromHistory, type ReviewEvent } from "../scientific-pedagogy/replay";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Expose the scheduler through the module's public API

The new runtime import of fsrsIntervalDays and fsrsMemoryFromHistory reaches directly into scientific-pedagogy/replay.ts, even though that module's explicit index.ts does not expose the replay implementation. This couples learning-studio to another module's internal evaluation file; publish a stable scheduler API or move the shared scheduling primitives behind an appropriate boundary.

AGENTS.md reference: AGENTS.md:L26-L26

Useful? React with 👍 / 👎.

const reviewLog = [...(state.reviewLog ?? []), { cardId, at: now.toISOString(), outcome }];
let next: ReviewState;
if (state.scheduler === "FSRS_4_5") {
const history = studioReviewEvents({ ...state, reviewLog }).filter((event) => event.itemId === cardId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep quiz attempts out of flashcard scheduling

When a learner completes a quiz and then rates the same flashcard within 12 hours, studioReviewEvents puts the quiz result immediately before the new rating, and fsrsMemoryFromHistory ignores the rating as a same-session repeat. Consequently, a correct quiz followed by an explicit FAIL schedules the card from the quiz success (four days for a new card) instead of the failure (one day); rebuild scheduling history from flashcard ratings only, or otherwise ensure the current rating is always applied.

Useful? React with 👍 / 👎.

const reviewLog = [...(state.reviewLog ?? []), { cardId, at: now.toISOString(), outcome }];
let next: ReviewState;
if (state.scheduler === "FSRS_4_5") {
const history = studioReviewEvents({ ...state, reviewLog }).filter((event) => event.itemId === cardId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Persist FSRS memory before truncating its source history

After the global review log exceeds MAX_REVIEW_LOG, writeStudioState persists only its last 2,000 entries; following a reload, this reconstruction therefore loses older per-card events and can treat a previously mature but infrequently reviewed card as new, resetting its next interval on the next rating. Persist per-card FSRS memory or compact history per card rather than making scheduling depend on a globally truncated log.

AGENTS.md reference: AGENTS.md:L30-L31

Useful? React with 👍 / 👎.

This branch was successfully deployed

1 active deployment
Preview — a6b1649f Deployed Oct 23, 2026 by vercel[bot]
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