Persist ranked-only mastery and use it consistently across progression, milestones, counts, and localized UI. Preserve mastery during history rebuilds, replay errors accurately, and generate replay-derived test profiles. Document the follow-up plan to remove the drill history cap.
3.5 KiB
Remove Drill History Cap
Context
The app currently truncates persisted drill_history to the most recent 500 drills in both:
finish_drill()finish_partial_drill()
This is implemented in src/app.rs by removing the oldest history entry once drill_history.len() > 500.
The original motivation for revisiting this came from the sticky-mastery work, where replay correctness becomes more important. But this history-cap issue is broader than mastery and should be handled as a separate task.
Current Findings
1. The cap affects persisted data, not just UI
lesson_history.json only retains the most recent 500 entries because the in-memory history is pruned before save.
2. Full-history replay already exists in some paths
The app already walks all retained drill_history in several places:
- startup:
App::new()callsrebuild_ngram_stats() - import: imported
drill_historyis followed byrebuild_ngram_stats() - delete-history-entry:
rebuild_from_history()replays remaining history, then callsrebuild_ngram_stats()
So removing the cap is not just a data-retention change. It also changes the amount of work done by:
- startup
- import
- delete-history rebuilds
3. Saves rewrite the full history file
After each completed or partial drill, save_data() writes the entire drill_history back to lesson_history.json.
That means uncapping history will likely increase:
- per-drill save latency
- JSON serialization cost
- disk usage
Questions To Resolve Later
- Should history become fully uncapped immediately, or should there be a configurable retention policy?
- Is JSON blob storage still acceptable for very large histories, or should history move to a more append-friendly format?
- Should startup continue rebuilding n-gram state from full history on every launch, or should the app persist derived caches?
- Is delete-history-entry expected to remain a full rebuild operation, or should that workflow be redesigned for large histories?
- Do we want the exported data format to always include full history, even if local persistence later changes format?
Likely Scope
At minimum, this future plan will need to cover:
Data retention behavior
- remove the 500-entry truncation logic in
src/app.rs - verify
save_drill_history()persists full history - update stale comments/docs that still describe history as capped
Performance analysis
- startup replay cost from
rebuild_ngram_stats() - import cost
- delete-history rebuild cost
- save latency from rewriting the full file every drill
Possible optimization directions
- keep full history but persist derived n-gram caches
- keep full history but move storage away from one monolithic JSON blob
- keep full history but make rebuilds incremental where possible
Non-Goals For This Stub
- choosing the final storage redesign now
- changing history persistence in the mastery plan
- making performance guarantees before measuring realistic history sizes
Files Likely Involved
src/app.rssrc/store/json_store.rssrc/store/schema.rsdocs/plans/2026-02-09-initial-plan.mddocs/plans/2026-02-22-n-gram-error-tracking-adaptive-drill-selection.md
Acceptance Criteria For The Future Task
To be defined in the full plan after deeper investigation, but likely to include:
- users retain full drill history
- startup performance remains acceptable
- per-drill save latency remains acceptable
- replay-derived features remain correct with large histories