The code is supposed to ensure the next interval is always one day longer than the previous one - at least with the v2 scheduler, this should happen after any fuzzing is applied. I presume the card history reflects repeated 2 day delays, and you have ruled out add-ons?
It looks like I had hit good (3) too many times before starting hitting hard (2). Next time I see a card as the one on the first post, I will look into their history.
Off-topic, I found that card where I keep hitting hard, but the hard interval does not increase:
I tried reading your solution but it looks like it requires an Addon to be installed. I rather have no addons messing with my review history/scheduling.
Then, I moved that card to a new deck ttt and created a filtered deck to review its cards ahead. And when the card showed up, it was with a hard (2) interval of 1 day:
This looks normal to me. You’ve reviewed the card ahead of schedule, and even with the shorter delay, you found it hard. You can see the code in question in _earlyReviewIvl()
After seeing another card with a hard (2 days), it also looks normal. Because my last interval was 1 day.
I am used to seeing a hard interval of 2 days, an easy interval of something like 5 or 7 days with an easy interval of something like 15 or 20 days, perhaps a month.
It just looks scary drop into a card and to see that my hard interval is 2 days, while my good interval is 1.2 months, and the easy interval is 3.3 months.
# next interval for card when answered early+correctly
def _earlyReviewIvl(self, card: Card, ease: int) -> int:
assert card.odid and card.type == CARD_TYPE_REV
assert card.factor
assert ease > 1
elapsed = card.ivl - (card.odue - self.today)
conf = self._revConf(card)
easyBonus = 1
# early 3/4 reviews shouldn't decrease previous interval
minNewIvl = 1
if ease == BUTTON_TWO:
factor = conf.get("hardFactor", 1.2)
# hard cards shouldn't have their interval decreased by more than 50%
# of the normal factor
minNewIvl = factor / 2
elif ease == BUTTON_THREE:
factor = card.factor / 1000
else: # ease == BUTTON_FOUR:
factor = card.factor / 1000
ease4 = conf["ease4"]
# 1.3 -> 1.15
easyBonus = ease4 - (ease4 - 1) / 2
ivl = max(elapsed * factor, 1)
# cap interval decreases
ivl = max(card.ivl * minNewIvl, ivl) * easyBonus
ivl = self._constrainedIvl(ivl, conf, prev=0, fuzz=False)
return ivl