lune-stone / anki-addon-limit-new-by-young

An add-on for Anki that can aid in maintaining a stable and efficient daily workload.
GNU Affero General Public License v3.0
7 stars 4 forks source link

Anki's "Custom study" interferes with limits by adjusting the record of how many cards have been studied #11

Closed aleksejrs closed 8 months ago

aleksejrs commented 8 months ago

Damien wrote:

Custom study extends the limits by adjusting the record of how many cards have been studied, so the changes will continue to apply after you make changes to the limits.

Because of that, this happens:

  1. set Today to 1
  2. review 1 card
  3. Custom study → Increase today’s new card limit by 1
  4. review 1 card
  5. increase today’s limit by 1

The limit is still “increased” by 1 over the Today limit, so there is another card available.

So if you increase the limit in a subdeck using "Custom study", it affects all the parent decks, and the add-on will not set Today to 0 that day.

lune-stone commented 8 months ago

I haven't had to test it yet, but I've pushed a change to a branch with what I think should fix this issue.

aleksejrs commented 8 months ago

That made it even worse; now learning a card increases the limit.

Unless I messed the code up, with "introduced:1" showing 6 cards (I think some of them had been rescheduled in the past and only reviewed now, not introduced as new), and supposedly 2 of them were learned using Custom study in a subsubdeck, the main deck shows:

introduced_today = 6
cSNCLCA = 2
introduced_today = 8
youngCount = 986
youngCardLimit = 400
load = 274.5680933596446
loadLimit = 275
newLimit = 8

The subsubdeck shows:

introduced_today = 3
cSNCLCA = 2
introduced_today = 5
youngCount = 0
youngCardLimit = 999999999
load = 15.182937599971702
loadLimit = 4
newLimit = 5
lune-stone commented 8 months ago

Debugging this has been a bit of a pain as introduced:1 seems to key off of the card's First Review which is not reset when a card is forgotten or even deleted/re-imported.

I could wipe the profile each time I test, or use some adhoc sql/code to clear this, but I suspect Anki's logic is using something else to track this number when calculating the internal new cards for the day, so that is likely where I will be looking next as I'd rather use the exact same values.

Also worth noting, custom study value is attached to the day it was done so that logic should be customStudy = 0 if mw.col.sched.today != deck['newToday'][0] else deck['newToday'][1]

lune-stone commented 8 months ago

After some digging I found mw.col._backend.counts_for_deck_today(did).new (new cards + custom study modifier) but then realized that deck['newToday'] is the same thing, and not the custom study modifier like I was originally thinking.

Hopefully that works better.

aleksejrs commented 8 months ago

"Limits start from top" is enabled.

I introduced 3 cards in the subsubdeck today. I don't remember if I used Custom study.

Main deck

new_today = -1 youngCount = 903 youngCardLimit = 400 load = 267.5014815477698 loadLimit = 275 newLimit = -1

No "Today only" limit is set, 3 new cards allowed.

subdeck

new_today = -1 youngCount = 0 youngCardLimit = 999999999 load = 23.0014268360174 loadLimit = 30 newLimit = 6

"Today only" set to 6, 2 new cards allowed.

subsubdeck

new_today = 0 youngCount = 0 youngCardLimit = 999999999 load = 19.264273553252046 loadLimit = 4 newLimit = 0

"Today only" set to 0, 0 new card allowed.

lune-stone commented 8 months ago

newLimit = -1

No "Today only" limit is set, 3 new cards allowed.

It's possible Anki is ignoring negative limits, which would explain why nothing was set for "Today only". If you change newLimit = max(0, max(...) + new_today) does it set the limit?

aleksejrs commented 8 months ago

Yes, it does.

Main deck

new_today = -1 youngCount = 902 youngCardLimit = 400 load = 267.6940464852919 loadLimit = 275 newLimit = 100

"Today only" set to 100.

Subdeck

new_today = -1 youngCount = 0 youngCardLimit = 999999999 load = 23.00146837812008 loadLimit = 30 newLimit = 999999998

Subsubdeck

new_today = 0 youngCount = 0 youngCardLimit = 999999999 load = 19.264315095354725 loadLimit = 4 newLimit = 999999999

aleksejrs commented 8 months ago

I changed the line to newLimit = max(0, max(0, min(maxNewCardsPerDay - new_today, youngCardLimit - youngCount, math.ceil(loadLimit - load))) + new_today)

Main deck

new_today = -1 youngCount = 898 youngCardLimit = 400 load = 276.5596081521139 loadLimit = 275 newLimit = 0

1 new card is allowed. Why is new_today = -1 anyway?

Subdeck

new_today = -1 youngCount = 0 youngCardLimit = 999999999 load = 23.027823356357253 loadLimit = 30 newLimit = 6

1 new card is allowed.

Subsubdeck

new_today = 0 youngCount = 0 youngCardLimit = 999999999 load = 19.29101947960168 loadLimit = 4 newLimit = 0

0 new cards are allowed.

lune-stone commented 8 months ago

Why is new_today = -1 anyway?

new_today is the sum of introduced cards and the custom study modifier. It's the modifier that allows the value to go negative.

newLimit = max(0, max(0, min(...

I've pushed a change that is slightly different in that the value of min(...) is preserved until the end.

With that update, the number seem correct to me as far as I can tell (can be tricky to see how many cards were introduced vs custom studied added new). The subsubdeck is over the load limit w/o custom study so 0 is correct. The subdeck is 30-23.03 round up to 7 from load, but since there is custom study that goes down to 6. Maindeck has too many young so even with the inherited custom study it is 0.

aleksejrs commented 8 months ago

Why is new_today = -1 anyway?

new_today is the sum of introduced cards and the custom study modifier. It's the modifier that allows the value to go negative.

I probably used Custom study yesterday to allow introducing 1 card in a deck sibling to the subsubdeck, but I didn't actually introduce the card. There is still 1 blue card now.

aleksejrs commented 8 months ago

Today I certainly didn't introduce any new cards, and introduced:1 shows no cards, but the main deck and the subdeck have new_today = -1. Other decks with the same substring in their names have 0. They "-1" decks have different presets, one of them shared with "0" decks.

lune-stone commented 8 months ago

Can you confirm how new_today is being set?

If it is using = deck['newToday'][1] that could explain the behavior, as it will be unchanged from yesterday before you start reviewing. = 0 if mw.col.sched.today != deck['newToday'][0] else deck['newToday'][1] is what the branch is currently using to check if the value is for today.

This code might be helpful in diagnosing. You can run it with debug console using ctrl+shift+;

for deckIndentifer in mw.col.decks.all_names_and_ids():
    deck = mw.col.decks.get(deckIndentifer.id)

    introduced_today = len(list(mw.col.find_cards(f'deck:"{deckIndentifer.name}" introduced:1')))
    today = mw.col.sched.today
    counts = mw.col._backend.counts_for_deck_today(deckIndentifer.id)
    (newTodayDay, newTodayAmount) = deck['newToday']
    (revTodayDay, revTodayAmount) = deck['revToday']

    print('name', deckIndentifer.name, 'did', deckIndentifer.id, 'conf', deck.get('conf'), 't', today, 'it', introduced_today, 'cn', counts.new, 'cr', counts.review, 'ntd', newTodayDay, 'nta', newTodayAmount, 'rtd', revTodayDay, 'rta', revTodayAmount)
aleksejrs commented 8 months ago

Yeah, I may have not reviewed any cards before posting that comment. Now it's 0, and no new cards are allowed anywhere in the main deck, even though there is a "-1" deck['newToday'][1] in one of them.

(main) conf 1 t 4384 it 0 cn 0 cr 34 ntd 4384 nta 0 rtd 4384 rta 34 (subdeck) conf 1698010111959 t 4384 it 0 cn 0 cr 0 ntd 4383 nta -1 rtd 4383 rta 18 (subsubdeck) conf 1698010111959 t 4384 it 0 cn 0 cr 0 ntd 4383 nta 0 rtd 4383 rta 15