fix(card): improve SM-2 algorithm compatibility with Anki

- Fix scheduleNewCard ease===3 (Good) to use steps[1] or graduate
- Fix scheduleLearningCard ease===2 (Hard) to repeat current step
- Ensure graduating cards get DEFAULT_FACTOR
- Fix interval calculations for learning card graduation

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-03-13 15:09:54 +08:00
parent f1eafa8015
commit 49ad953add

View File

@@ -95,14 +95,24 @@ function scheduleNewCard(ease: ReviewEase, currentFactor: number): {
} }
if (ease === 3) { if (ease === 3) {
if (SM2_CONFIG.LEARNING_STEPS.length >= 2) {
return { return {
type: CardType.LEARNING, type: CardType.LEARNING,
queue: CardQueue.LEARNING, queue: CardQueue.LEARNING,
ivl: 0, ivl: 0,
due: Math.floor(Date.now() / 1000) + SM2_CONFIG.LEARNING_STEPS[0] * 60, due: Math.floor(Date.now() / 1000) + SM2_CONFIG.LEARNING_STEPS[1] * 60,
newFactor: currentFactor, newFactor: currentFactor,
}; };
} }
const ivl = SM2_CONFIG.GRADUATING_INTERVAL_GOOD;
return {
type: CardType.REVIEW,
queue: CardQueue.REVIEW,
ivl,
due: calculateDueDate(ivl),
newFactor: SM2_CONFIG.DEFAULT_FACTOR,
};
}
const ivl = SM2_CONFIG.EASY_INTERVAL; const ivl = SM2_CONFIG.EASY_INTERVAL;
const newFactor = SM2_CONFIG.DEFAULT_FACTOR + SM2_CONFIG.FACTOR_ADJUSTMENTS[4]; const newFactor = SM2_CONFIG.DEFAULT_FACTOR + SM2_CONFIG.FACTOR_ADJUSTMENTS[4];
@@ -153,16 +163,24 @@ function scheduleLearningCard(ease: ReviewEase, currentFactor: number, left: num
}; };
} }
if (stepIndex < steps.length - 1) { if (stepIndex < steps.length - 1) {
const nextStep = stepIndex + 1;
return { return {
type: CardType.LEARNING, type: CardType.LEARNING,
queue: CardQueue.LEARNING, queue: CardQueue.LEARNING,
ivl: 0, ivl: 0,
due: Math.floor(Date.now() / 1000) + steps[nextStep] * 60, due: Math.floor(Date.now() / 1000) + steps[stepIndex] * 60,
newFactor: currentFactor, newFactor: currentFactor,
newLeft: nextStep * 1000 + (totalSteps - nextStep), newLeft: left,
}; };
} }
const ivl = SM2_CONFIG.GRADUATING_INTERVAL_GOOD;
return {
type: CardType.REVIEW,
queue: CardQueue.REVIEW,
ivl,
due: calculateDueDate(ivl),
newFactor: SM2_CONFIG.DEFAULT_FACTOR,
newLeft: 0,
};
} }
if (ease === 3) { if (ease === 3) {