Parties enregistrées, branches et export SGF (étape 1b) #37

Manually merged
pierre merged 8 commits from parties-enregistrees into main 2026-11-03 19:55:20 +00:00
4 changed files with 12 additions and 99 deletions
Showing only changes of commit 2c4448549d - Show all commits
@@ -94,3 +94,13 @@ les justifie pas.
dépendances seront fixés avec le socle, à la fin de l'étape 0.
- Les sous-agents reçoivent ces règles dans leurs consignes ; `CLAUDE.md` y
renvoie.
### 2026-11-03 — Le stockage des parties est un format durable
Avec les parties enregistrées (étape 1b), le schéma IndexedDB (base
« ustagammon », version 1 : magasins `games`, `journals`, `settings`) et les
clés `localStorage` de l'application (`ustagammon.settings`,
`ustagammon.last-board`, et le repli des parties) rejoignent le journal
d'événements parmi les formats durables : toute modification passe par une
montée de version avec migration testée, jamais par une réécriture qui
perdrait les parties des joueurs.
+1 -1
View File
@@ -18,7 +18,7 @@ Repris du cadrage (modules, écrans clés, IA générative en V1) et des ADR 001
| Sous-étape | Contenu | Dépend de |
| --- | --- | --- |
| 1a. Moteur pour l'analyse (fait) | Niveaux de jeu (plis et bruit de GNU Backgammon : débutant à expert), classement des coups d'un jet avec équités, analyse d'un coup joué et d'une décision de videau, chance d'un jet ; exposés par `engine.h`, `engine-cli` et le Worker, avec positions de référence comparées à gnubg de bureau | — |
| 1b. Parties enregistrées | Stockage IndexedDB derrière l'interface de stockage existante : plusieurs parties, reprise automatique, branches (« Rejouer d'ici » crée une branche, l'originale reste intacte et rechargeable), export SGF avec variantes | — |
| 1b. Parties enregistrées (fait) | Stockage IndexedDB derrière l'interface de stockage existante : plusieurs parties, reprise automatique, branches (« Rejouer d'ici » crée une branche, l'originale reste intacte et rechargeable), export SGF avec variantes | — |
| 1c. Match et réglages | Partie libre ou match en N points, règle Crawford, règle Jacoby, choix du niveau de l'ordinateur, conseil du maître activable ou non ; écran de nouvelle partie | 1a, 1b |
| 1d. Conseil du maître | Après chaque coup du joueur, jamais avant (ADR 0011) : appréciation du moteur (bon coup, imprécision, erreur, gaffe) avec mot, icône et couleur, phrase du maître fondée sur les chiffres du moteur, coup recommandé montré sur demande ; aussi pour les décisions de videau ; calcul en arrière-plan sans retarder le jeu | 1a |
| 1e. Fin de partie et analyse | Bilan (ADR 0011) : résultat, coups par appréciation, taux d'erreur comparé à la chance, « le coup à revoir » ; écran d'analyse : graphe d'équité (toucher un point ouvre la position), liste des erreurs filtrable, visualiseur pas à pas coup joué contre meilleur coup, « Rejouer d'ici » | 1a, 1b, 1d |
@@ -1,97 +0,0 @@
# Parties enregistrées, branches et export SGF (1b)
- **Date** : 2026-11-03
- **Étape** : 1b (`docs/etape-1.md`)
- **Statut** : prévu (lancé après la fusion de 0e.1)
- **Exécutant** : sous-agent general-purpose, dans un worktree
## Objectif
Garder toutes les parties du joueur sur le téléphone, avec leurs branches, et
les exporter au format SGF de GNU Backgammon.
## Consignes
ADR 0007 (domaine pur, stockage derrière une interface), ADR 0008 (scénarios
et glossaire). Aucune nouvelle dépendance : l'API IndexedDB du navigateur
directement.
1. **Stockage IndexedDB** derrière l'interface de `app/src/storage/` : une
liste de parties (identifiant, date de début et de dernière action,
adversaire et niveau, score, état en cours ou finie, résultat) et le
journal d'événements de chacune. Migration transparente de la partie
en cours enregistrée aujourd'hui dans `localStorage`. Si IndexedDB est
indisponible (navigation privée), repli sur le comportement actuel.
2. **Branches** : le journal est déjà un arbre (événements avec parent,
`goBackTo`). Exposer dans le domaine la liste des branches d'une partie
(feuilles de l'arbre, avec le coup d'origine) et le passage de l'une à
l'autre. « Rejouer d'ici » depuis un coup passé crée une branche ; la
branche d'origine reste intacte et rechargeable. Pas d'écran d'analyse ici
(1e) : un accès minimal suffit pour le test (menu « Mes parties » :
reprendre une partie, voir ses branches).
3. **Nouvelle partie annulable** : l'arbitrage UX (plan
`2026-11-03-revision-ux.md`, point 3) prévoit « Reprendre l'ancienne »
pendant 10 s. Fournir l'API de stockage qui le permet (reprendre une partie
par son identifiant) ; l'interface viendra avec la révision UX.
4. **Export SGF** : une partie (et ses branches en variantes) au format SGF
de GNU Backgammon, téléchargeable depuis « Mes parties ». Vérification par
le gnubg de bureau de référence (Docker existant) : le fichier exporté se
charge sans erreur et ses positions successives sont les mêmes que celles
du journal, sur des parties générées par les tests.
5. Scénarios Gherkin : reprendre une partie parmi plusieurs, rejouer d'ici
sans perdre l'original, exporter une partie. Fiches du glossaire pour les
nouveaux termes (branche, SGF…).
`make lint`, `make test` et `make test-browser` passent (ajouter au test
navigateur : deux parties enregistrées, reprise de la première après
rechargement). Commits fréquents ; pas de push ni de MR.
## Critères de réussite
- Après rechargement, la liste des parties et chaque branche sont intactes.
- Un SGF exporté se charge dans gnubg de bureau avec les mêmes positions.
- Les trois commandes de test passent.
## Résultat
Réalisé le 2026-11-03 sur la branche `parties-enregistrees`, fusionnée avec
main après la révision UX (MR !35).
- **Stockage** (`app/src/storage/`) : `GameLibrary` (list, load, save,
remove, current, setCurrent) sur IndexedDB (base « ustagammon » v1 :
magasins games, journals, settings ; résumé et journal dans la même
transaction), en repli sur localStorage puis sur la mémoire. Opérations
exécutées dans l'ordre des appels. La partie de l'étape 0
(`ustagammon.current-game`) est migrée puis effacée. `GameSession` tient
la partie à l'écran : nouvelle partie, « Reprendre l'ancienne » (relue
par son identifiant, la nouvelle est supprimée), reprise d'une partie ou
d'une branche.
- **Domaine** : `branches(journal)` et `switchToBranch` (branches.ts),
`Game.branches` et `Game.switchBranch`, résumé d'une partie
(saved-game.ts), export SGF de GNU Backgammon avec les branches en
variantes, la branche courante d'abord (sgf.ts).
- **Interface** : « Mes parties », ligne du menu en feuille, ouvre une
feuille (games-view.ts) : reprendre une partie ou une branche (changement
de partie à l'écran, sans recharger), exporter en SGF, supprimer en deux
touchers (jamais la partie affichée).
- **Vérification SGF** : `tests/test_web.sh` joue 6 parties sur le vrai
moteur (complètes, branches, videau, positions particulières), les
exporte (9 fichiers, un par branche) et les fait relire par le gnubg de
référence (`tests/sgf/check.py`) : après chaque coup, sa position égale
celle du journal, et le résultat concorde. Une altération volontaire d'un
coup ou de la position de départ est détectée.
- **Scénarios** : `docs/scenarios/mes-parties.feature` (reprendre une partie
parmi plusieurs, rejouer d'ici sans perdre l'original, exporter) ; le
scénario « Reprendre l'ancienne » de `regler-l-application.feature` passe
par la session. Glossaire : partie-enregistree.md, sgf.md, branche.md
(code: Branch).
- **Tests** : `make lint`, `make test` (10/10, 20 scénarios) et
`make test-browser` (Chromium et Firefox : parties listées, SGF
téléchargé, première partie reprise sans rechargement, « Reprendre
l'ancienne » sans partie en trop) passent.
Limites connues : gnubg 1.08 ne lit que la première variante d'un SGF ;
l'enregistrement n'est pas attendu (une fermeture dans les millisecondes
qui suivent une action peut la perdre) ; pas de score de match avant 1c ;
le schéma IndexedDB devient un contrat durable (amendement de l'ADR 0007 à
envisager). L'adresse `#/parties` viendra avec 0e.4.
@@ -2,7 +2,7 @@
- **Date** : 2026-11-03
- **Étape** : 0e.4 (feuille de route)
- **Statut** : prévu (après la fusion de la révision UX et de 1b)
- **Statut** : prévu
- **Exécutant** : sous-agent general-purpose, dans un worktree
## Objectif