--- name: gametime-architecture-score-chrono description: memory note gametime-architecture-score-chrono metadata: type: project --- # GameTime — Cadrage Architect : score chronométré (ticket #18, 2026-07-18) ## Stockage validé - `actualScoreTimeMs` (nullable) sur `ActiveSetResult` et `WorkoutHistorySetResult`, distinct de `actualScore`. - `targetScoreTimeMs` sur `ProgramExercise`, `targetScoreTimeMsOverride` sur `WorkoutTemplateExerciseOverride`, distincts de `targetScore`/`targetScoreOverride`. - Invariant : `manual` utilise `actualScore/targetScore` ; `stopwatch` utilise `actualScoreTimeMs/targetScoreTimeMs` ; jamais les deux familles remplies simultanément. `skipped` implique aucune valeur `actual*` (y compris `actualScoreTimeMs`). ## État transitoire du chrono Nouvelle table Drift `ActiveScoreStopwatchState`, sur le même principe que `ActiveRestState` (horodatages persistés, pas de compteur mémoire) : - clé logique : `activeWorkoutSessionId + programIndex + exerciseIndex + setIndex` - `status` : `running | stopped` - `startedAt`, `accumulatedMs`, `stoppedAt?` - Absence de ligne = chrono non démarré. - À la validation de la série, copier la durée finale vers `ActiveSetResult.actualScoreTimeMs`. - Pause de séance : si `running`, figer `accumulatedMs` ; reprise explicite après resume (pas de décompte pendant la pause). - Terminer la série avec chrono `running` → auto-stop puis enregistrement (comportement UX demandé). ## Propagation du mode (snapshot pattern existant, réutilisé tel quel) `ScoreInputMode` (`manual|stopwatch`) : source de vérité sur `Exercise`, copié dans `ProgramExercise`, puis dans le snapshot de séance (`WorkoutTemplateProgram`/exercice snapshotté), puis dans `ActiveSetResult` et `WorkoutHistorySetResult` pour affichage autonome sans dépendre de la source. **Important** : `WorkoutTemplateExerciseOverride` ne porte JAMAIS le mode lui-même (cohérent avec la règle produit déjà en place : l'override en séance-modèle ne change que des valeurs numériques, jamais la structure/le mode) — seulement `targetScoreTimeMsOverride` en plus des overrides numériques existants. ## Migration Drift Le schéma est actuellement en `schemaVersion = 2` (ticket #21). Le ticket #18 doit passer en **3** : ajout des colonnes mode/chrono sur les tables concernées + création de la table `ActiveScoreStopwatchState`, migration `from < 3`.