Projet Niv. 5 — ⭐ Drill v2 : la révision espacée
Le brief : le capstone. Drill apprend de VOS erreurs : les questions ratées reviennent plus souvent (boîtes de Leitner), un mode « Révision » cible vos faiblesses, les stats montrent la progression réelle. La boucle pédagogique se ferme — sur l’app ET sur vous.
Ce que vous allez pratiquer
TOUT — c’est le principe d’un capstone : l’algorithme en lib/ pur testé à fond, une migration v2 sur des données EXISTANTES (vos mois d’historique !), l’évolution d’une app en production (OTA, versionnage), et les décisions de conception en autonomie. Chapitres liés : 6.3, 8.2, 8.3, 12.5-12.6, 14.2.
Le système de Leitner (la spec)
Chaque question connue de l’utilisateur vit dans une boîte 1-5 :
- Nouvelle question rencontrée → boîte 3.
- Bonne réponse → boîte +1 (max 5). Mauvaise → boîte 1 (retour à la case départ).
- La boîte définit l’échéance de révision : B1 = 1 jour, B2 = 3 j, B3 = 7 j, B4 = 14 j, B5 = 30 j.
- Une question est due si
now >= lastAnswered + interval(box).
Le mode Révision tire d’abord les questions DUES (les plus anciennes d’abord), complète avec des nouvelles si besoin. C’est SM-0 simplifié — largement suffisant, et VOS données d’answers depuis la P8 alimentent tout.
L’architecture recommandée
- La migration v2 (le moment le plus formateur du projet) :
-- v2 : l'état de révision par question
CREATE TABLE review_state (
question_id TEXT PRIMARY KEY, -- l'id STABLE du repo (le contrat du ch. 7.3 paie ici)
box INTEGER NOT NULL DEFAULT 3,
last_answered_at INTEGER NOT NULL,
times_seen INTEGER NOT NULL DEFAULT 0
);
-- + le BACKFILL : reconstruire l'état depuis la table answers existante
INSERT INTO review_state (question_id, box, last_answered_at, times_seen)
SELECT question_id,
MAX(1, MIN(5, 3 + SUM(CASE WHEN correct THEN 1 ELSE -2 END))), -- heuristique
MAX(rowid) /* … le vrai last : sous-requête sur answers */, COUNT(*)
FROM answers GROUP BY question_id;Le backfill est la leçon : vos mois d’historique deviennent l’état initial — une migration qui TRANSFORME des données, pas juste un ALTER. (L’heuristique exacte est à vous : documentez-la dans la migration même.)
- lib/leitner.ts, pur, testé AVANT :
nextBox(box, correct),isDue(state, now),pickReviewQuestions(states, all, count, now, rng)— l’horloge et le hasard en paramètres (les leçons de la P14 appliquées d’instinct). - La machine d’état ne change PAS : le mode Révision est un
start()avec un tirage différent — la conception de la P6 encaisse la v2 sans broncher (si ce n’est pas le cas, c’est un signal d’architecture à corriger d’abord). - L’UI : un bouton « 🔁 Réviser (12 dues) » sur l’accueil, le badge de boîte sur l’explication (« cette question monte en boîte 4 ! »), et l’écran stats enrichi (répartition des boîtes par thème — la « santé » de votre mémoire).
Les jalons
- lib/leitner.ts + la suite de tests complète (les 5 boîtes, les échéances, le tirage).
- La migration v2 avec backfill — testée sur une COPIE de votre vraie base (adb pull !).
- L’enregistrement : chaque answer met à jour review_state (dans la même transaction).
- Le mode Révision (tirage dues-d’abord) + le compteur sur l’accueil.
- Les stats de boîtes + le badge de progression sur l’explication.
- La release : bump 2.0.0, build, OTA de baseline, tag — le rituel complet du ch. 12.6, en conditions réelles.
Critères de réussite
- La suite leitner passe — y compris « due à minuit moins une » (l’horloge injectée)
- La migration backfill sur votre vraie base : l’état initial est PLAUSIBLE (vos questions ratées sont bien en boîtes basses)
- Une session de révision de 10 questions contient d’abord TOUTES les dues
- Rater une question de boîte 5 la renvoie en boîte 1 (et ça se VOIT dans l’UI)
- Le mode Quiz classique n’a pas bougé d’un pixel (la v2 est additive)
- Drill 2.0.0 tourne sur votre téléphone, l’historique v1 intact — et vous révisez pour de vrai
Pièges connus
- Le backfill sur la VRAIE base se teste sur une copie d’abord :
adb pulldu fichier drill.db (via run-as ou le backup — ou plus simple : testez sur l’émulateur seedé). Une migration ratée sur ses propres données de production est la leçon qu’on ne veut apprendre qu’une fois — en TP. - Les questions SUPPRIMÉES du repo (le contrat « jamais réutiliser un id », ch. 7.3) : leur review_state orphelin est inoffensif — mais le tirage doit ignorer les states sans question correspondante (le LEFT JOIN mental).
- N’inventez pas SM-2/Anki d’entrée (ease factors, intervalles flottants) : Leitner d’abord, l’upgrade ensuite si VOS données montrent des limites. Commencer simple est une compétence.
🏁 Et après ? Vous avez une app de révision alimentée par un repo de questions que l’IA peut remplir à volonté (le README-contrat du ch. 7.3), un pipeline de release complet, et cinq apps de productivité à votre main. La suite logique : les milliers de questions dans drill-questions (les sessions de génération), et — qui sait — la P13 pour de vrai le jour où quelqu’un vous demande « elle est où, ton app ? ». Le cours s’arrête ici ; la pratique, elle, commence.