chore(tickets): met à jour le carnet du ticket #84 (rapport QA GO)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 14:01:07 +02:00
parent 81141d4b3e
commit 7617aa694e

View File

@ -796,4 +796,60 @@ B1/B2/B3 backend sont complets et testés. DevFrontend peut enchaîner F1 (déj
**Lot frontend F1/F2 : GO.** **Lot frontend F1/F2 : GO.**
Étape suivante : QA pour validation finale. Étape suivante : QA pour validation finale.
# QA — Validation finale #84
## Méthode
Relecture indépendante du cadrage UX et Architect vs implémentation (`lib/application/use_cases.dart`, `lib/presentation/profile_screen.dart`), relecture de la couverture de test (`test/application/use_cases_test.dart`, `test/infrastructure/drift_repositories_test.dart`, `test/presentation/profile_screen_test.dart`), puis ré-exécution réelle des commandes.
## Conformité cadrage
- **Format `.gametime` v1** : envelope, `kind`, `formatVersion`/`minSupportedFormatVersion`, `counts`, `data`, `mediaFiles` — conforme au cadrage Architect (`LocalBackupCodec.encode/decode`, `lib/application/use_cases.dart:53-145`).
- **Validation de compatibilité** : `invalidFile` (kind/racine), `incompatibleFormat` (version absente/<1), `newerVersion` (version future), `corrupted` (data malformé) tous les cas du cadrage sont bien distingués et testés.
- **Blocage séance active** : vérifié avant toute mutation (`importFrom`, ligne 197), pour `merge` et `replaceAll` indifféremment conforme.
- **Transaction tout-ou-rien** : erreur générique pendant `applyImportSnapshot` `importFailedNoMutation`, rollback confirmé par test dédié (round-trip avec ressource cassée aucune insertion partielle, `drift_repositories_test.dart` ~ligne 673-732).
- **Fusionner (LWW)** : nouvelle ressource insérée, ressource plus récente dans le fichier remplace le local, local plus récent ignoré couvert par test round-trip dédié.
- **Remplacer tout** : purge logique (soft-delete + change_log tombstone) + import intégral, compte/tokens/sync préservés couvert par test dédié (`local backup replaceAll soft deletes absent data and imports file`).
- **UX Profil** : tous les libellés exacts du cadrage sont présents mot pour mot dans `profile_screen.dart` (`Sauvegarde locale`, `Exporter mes données`, `Préparation de l'export...`, `Lecture de la sauvegarde...`, `Importer cette sauvegarde ?`, `Fusionner`, `Remplacer tout`, doubles confirmations, tous les messages d'erreur typés, message compte connecté). Cas app locale vide correctement simplifié (`_confirmSimpleImport` avec bouton unique `Importer`).
- **Aucun libellé à éviter** (`Dump`, `Backup DB`, etc.) n'apparaît dans le code.
## Couverture de test — vérifiée par lecture directe
- Round-trip exportimport Fusionner et Remplacer tout via le vrai codec : présents et couvrent insertion, préservation, tags, historique complet.
- Détection fichier invalide / corrompu / version incompatible / version future : couverte côté `use_cases_test.dart` (codec) et côté widget (`profile_screen_test.dart` : message dédié affiché).
- Blocage séance active : couvert côté repository ET côté widget.
- Comptage médias manquants/corrompus : couvert (`missingMediaCount` reflète un échec de checksum, régression testée explicitement suite au fix DevBackend).
- Double confirmation destructive Remplacer tout : couverte côté widget, y compris annulation de la seconde confirmation.
- Annulation sélection fichier silencieuse : couverte.
## Ré-exécution des commandes (QA, indépendante)
```
$ flutter test --no-pub
00:08 +238 -1: Some tests failed.
Failing tests:
test/infrastructure/drift_repositories_test.dart: exercise repository round-trips exercise option combinations stopwatch score with stopwatch scored steps
```
238 tests exécutés, 1 seul échec identique à celui documenté par DevBackend/Main (contrainte FOREIGN KEY sur media assets de fixture, préexistant, sans rapport avec #84). Aucune régression détectée.
```
$ dart analyze
24 issues found. (uniquement des `info`, deprecations Flutter préexistantes + 2 `use_build_context_synchronously` déjà présents ailleurs dans profile_screen.dart, hors code #84)
```
Propre : aucun `warning`/`error`.
## Écarts non bloquants (confirmés par QA)
1. **Pas de message dédié « Espace insuffisant »** : le cadrage UX rend ce message conditionnel Si l'erreur vient d'un manque d'espace disque et que l'app peut le savoir »). L'implémentation retombe sur le message générique `Export impossible pour le moment.` dans tous les cas d'erreur d'export. Acceptable au MVP : le cadrage n'impose pas cette distinction, seulement l'autorise.
2. **État intermédiaire d'import non distingué en deux phases** : `_importBusy` réutilise le même indicateur/libellé (`Lecture de la sauvegarde...`) pour la phase de lecture/preview ET pour la phase d'application (merge/replace). Le cadrage ne demande explicitement ce libellé que pour la validation initiale ; il n'y a pas d'exigence UX d'un libellé distinct pendant l'application. Acceptable au MVP, cohérence UX conservée (bouton désactivé dans les deux cas, pas d'action concurrente possible).
Aucun autre écart trouvé entre cadrage UX/Architect et implémentation.
## Verdict
**GO.**
Implémentation conforme au cadrage UX et Architect, couverture de test adéquate sur les invariants critiques (LWW, transaction tout-ou-rien, blocage séance active, validation de version, comptage médias), suite complète verte à l'exception de l'échec préexistant hors périmètre, `dart analyze` propre. Les 2 écarts relevés par DevFrontend sont non bloquants et n'appellent pas de correction avant clôture.
Étape suivante : Git peut clôturer le ticket #84.