# 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.