---
name: gametime-architecture-step-chaining-override
description: memory note gametime-architecture-step-chaining-override
metadata:
  type: project
---
# GameTime — Architecture auto-enchaînement configurable des chronos d'étapes

Décision d'architecture pour le ticket #73, basée sur `gametime-ux-step-chaining-override` et `gametime-architecture-exercise-steps`.

## Décision métier

Ajouter un réglage booléen : `autoStartNextTimedStep`.

Libellé UX : `Enchaîner automatiquement les chronos consécutifs`.

Valeur par défaut : `true`, pour préserver le comportement livré par les tickets #54/#60.

Portée exacte : le réglage ne concerne que le cas `Étape Temps -> Étape Temps`. Il ne change pas :
- Temps -> Répétitions : attente manuelle comme aujourd'hui.
- Répétitions -> Temps : démarrage possible après action utilisateur comme aujourd'hui.
- Fin de série : la séquence ne termine toujours pas automatiquement la série.

## Stockage / modèle domain

### Exercise

Ajouter :

```dart
final bool autoStartNextTimedStep;
```

- non-null ;
- défaut `true` ;
- présent même si `steps` est vide, mais sans effet tant qu'il n'y a pas de séquence avec deux étapes Temps consécutives.

### ProgramExercise

Ajouter deux champs :

```dart
final bool autoStartNextTimedStepSnapshot;
final bool? autoStartNextTimedStepOverride;
```

Raison : `ProgramExercise` est à la fois snapshot d'exercice et configuration programme. Il faut pouvoir revenir au réglage exercice sans dépendre de l'Exercise vivant, puisque les programmes existants restent indépendants des modifications ultérieures de bibliothèque.

Résolution programme :

```dart
programEffective = autoStartNextTimedStepOverride ?? autoStartNextTimedStepSnapshot;
```

À propager impérativement dans :
- `ProgramExercise.snapshotFromExercise` ;
- `ProgramExercise.toSnapshotJson()` ;
- `ProgramExerciseConfig` ;
- `_ProgramExerciseDraft` ;
- mappers Drift ;
- copie/share/import payloads.

Point d'attention #72 : ne pas oublier la propagation UI draft/config comme cela est arrivé pour `exerciseStepsSnapshot`.

### WorkoutTemplateExerciseOverride

Ajouter :

```dart
final bool? autoStartNextTimedStepOverride;
```

Décision consciente : cela élargit légèrement la règle historique des overrides de séance-modèle. Jusqu'ici, l'override ne portait que des valeurs numériques de série. Ce booléen est accepté dans `WorkoutTemplateExerciseOverride` parce qu'il ne modifie ni la structure, ni les mesures actives, ni la liste/l'ordre des exercices/étapes. Il modifie uniquement un comportement d'exécution local et nullable, avec héritage explicite.

Résolution séance :

```dart
effective = templateOverride.autoStartNextTimedStepOverride
  ?? programExercise.autoStartNextTimedStepOverride
  ?? programExercise.autoStartNextTimedStepSnapshot;
```

Null signifie toujours héritage.

## Drift / migration

Le schéma actuel vérifié est `schemaVersion = 13`. Le ticket #73 doit passer à `schemaVersion = 14`.

Migration recommandée :
- `exercises.auto_start_next_timed_step BOOLEAN NOT NULL DEFAULT true`.
- `program_exercises.auto_start_next_timed_step_snapshot BOOLEAN NOT NULL DEFAULT true`.
- `program_exercises.auto_start_next_timed_step_override BOOLEAN NULL`.
- `workout_template_exercise_overrides.auto_start_next_timed_step_override BOOLEAN NULL`.

Les snapshots JSON anciens n'auront pas ces champs : les parseurs doivent traiter l'absence comme `true`.

## Résolution pendant l'exécution

La valeur effective doit être disponible dans le snapshot résolu de séance ou, a minima, dans `_StepSequenceContext`.

Approche recommandée :
- lors de `startFromTemplate`, inclure l'override séance dans `resolvedTemplateSnapshotJson` comme les autres overrides ;
- lors de `_findExerciseSnapshot` / `_stepContext`, calculer ou exposer `autoStartNextTimedStepEffective` ;
- `ActiveExerciseStepUseCases` ne doit pas relire les entités vivantes Exercise/Program/Template. Il travaille uniquement sur le snapshot de session, comme le reste de l'exécution.

Cela garantit que reprendre une séance en cours garde le comportement décidé au lancement, même si l'utilisateur modifie ensuite l'exercice ou le programme source.

## État `Chrono suivant prêt`

Ne pas ajouter de nouveau statut Drift/domain pour v1.

Réutiliser `ActiveExerciseStepProgressStatus.stoppedTimer` : il signifie déjà qu'une étape chronométrée courante est prête mais non lancée (`startedAt == null`, `accumulatedMs == 0`).

Ne pas utiliser `waitingManual`, réservé aux étapes de type `reps`.

Le libellé UX `Chrono suivant prêt` est dérivé côté présentation/use case view quand :
- `state.status == stoppedTimer` ;
- l'étape courante est `time` ;
- l'étape précédente effective était aussi `time` ;
- `autoStartNextTimedStepEffective == false` ;
- un résultat completed/skipped existe pour l'étape précédente ou on vient de la transition timer expirée.

Pour la première étape chronométrée de la séquence, l'UI garde `Démarrer la séquence`. Pour une étape chrono prête après une étape Temps avec auto-enchaînement désactivé, l'UI affiche `Chrono suivant prêt` + `Démarrer le chrono`.

## `_advanceState` et `_autoAdvanceElapsedTimers`

Comportement actuel : `_autoAdvanceElapsedTimers` consomme l'overflow d'un timer expiré et peut démarrer automatiquement les timers suivants.

Nouveau comportement :
- si `autoStartNextTimedStepEffective == true`, comportement inchangé ;
- si `false` et que l'étape expirée est suivie d'une étape `time`, enregistrer le résultat de l'étape expirée, avancer la position vers l'étape suivante, puis s'arrêter en `stoppedTimer` avec `startedAt = null`, `accumulatedMs = 0` ;
- dans ce cas, ne pas transférer `overflowMs` au chrono suivant ;
- après kill/reprise, `_autoAdvanceElapsedTimers` doit s'arrêter exactement au premier `Chrono suivant prêt` et ne jamais avancer plus loin sans action utilisateur ;
- si l'étape suivante est `reps`, comportement inchangé : `waitingManual` ;
- si la dernière étape d'un passage est `time` et que le passage suivant commence par `time`, appliquer la même règle.

## Invariants

- Le réglage ne change jamais les résultats déjà enregistrés.
- Le réglage ne crée pas une pause de séance : le temps total de séance continue selon les horodatages de session.
- L'état `Chrono suivant prêt` est persistant car représenté par la ligne `ActiveExerciseStepProgressState` en `stoppedTimer` sur la bonne étape/passage.
- Les anciens exercices/programmes/templates doivent migrer avec comportement effectif `true`.
- Les overrides restent nullable pour permettre les actions UX `Revenir au réglage de l'exercice` et `Revenir au réglage du programme`.

## Tickets créés

- #75 `[DevBackend] Modèle et migration pour auto-enchaînement des chronos d'étapes`.
- #76 `[DevBackend] Résolution effective et auto-advance des chronos d'étapes`, dépend de #75.
- #77 `[DevFrontend] Réglages auto-enchaînement exercice, programme et séance`, dépend de #75.
- #78 `[DevFrontend] État d'exécution Chrono suivant prêt`, dépend de #76 et #77.
- #79 `[QA] Validation auto-enchaînement configurable des chronos d'étapes`, dépend de #78.

Ordre recommandé : #75 -> #76 et #77 en parallèle -> #78 -> #79.