merge(main): validation auto-enchaînement configurable des chronos d'étapes (ticket #79)
Fusionne feature/step-chaining-79-qa — analyze propre (mêmes infos préexistantes), 154/154 tests verts, build APK debug validé. Aucun bug de production trouvé en QA, couverture de test supplémentaire uniquement (reprise après kill d'app, enchaînement désactivé). Clôture le chantier "auto-enchaînement des chronos d'étapes" (#73, tickets #75 à #79). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
issueRef: "#78"
|
issueRef: "#78"
|
||||||
version: 1
|
version: 2
|
||||||
updatedBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"}
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
updatedAt: 1784547239512
|
updatedAt: 1784549136530
|
||||||
---
|
---
|
||||||
|
|||||||
@ -2,15 +2,15 @@
|
|||||||
id: "e7769413-3d3d-48af-b55e-361c69aef4b2"
|
id: "e7769413-3d3d-48af-b55e-361c69aef4b2"
|
||||||
number: 78
|
number: 78
|
||||||
title: "[DevFrontend] État d'exécution Chrono suivant prêt"
|
title: "[DevFrontend] État d'exécution Chrono suivant prêt"
|
||||||
status: "open"
|
status: "qa"
|
||||||
priority: "medium"
|
priority: "medium"
|
||||||
sprint: null
|
sprint: null
|
||||||
links: [{"target":"#73","kind":"relatesTo"},{"target":"#76","kind":"dependsOn"},{"target":"#77","kind":"dependsOn"}]
|
links: [{"target":"#73","kind":"relatesTo"},{"target":"#76","kind":"dependsOn"},{"target":"#77","kind":"dependsOn"}]
|
||||||
agentRefs: [{"agentId":"9933c93a-b8a1-4164-a3bb-7063fdad747d","role":"assigned"}]
|
agentRefs: [{"agentId":"9933c93a-b8a1-4164-a3bb-7063fdad747d","role":"assigned"}]
|
||||||
createdBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"}
|
createdBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"}
|
||||||
updatedBy: {"kind":"agent","agent_id":"f8f40941-ecf7-4830-b9de-8818a099f448"}
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
||||||
createdAt: 1784547239512
|
createdAt: 1784547239512
|
||||||
updatedAt: 1784547239512
|
updatedAt: 1784549136530
|
||||||
version: 1
|
version: 2
|
||||||
---
|
---
|
||||||
Adapter l'écran d'exécution des étapes pour afficher `Chrono suivant prêt` quand une étape Temps est prête après une étape Temps et que l'auto-enchaînement effectif est désactivé. Réutiliser `stoppedTimer` côté domaine; l'UI dérive le libellé/bouton depuis l'étape courante, le résultat précédent et la valeur effective. Bouton `Démarrer le chrono`, pas de pause séance, pas de rouge/erreur. Après kill/reprise, l'écran doit revenir à cet état sans démarrage automatique.
|
Adapter l'écran d'exécution des étapes pour afficher `Chrono suivant prêt` quand une étape Temps est prête après une étape Temps et que l'auto-enchaînement effectif est désactivé. Réutiliser `stoppedTimer` côté domaine; l'UI dérive le libellé/bouton depuis l'étape courante, le résultat précédent et la valeur effective. Bouton `Démarrer le chrono`, pas de pause séance, pas de rouge/erreur. Après kill/reprise, l'écran doit revenir à cet état sans démarrage automatique.
|
||||||
@ -883,13 +883,13 @@
|
|||||||
"issueRef": "#78",
|
"issueRef": "#78",
|
||||||
"path": "78",
|
"path": "78",
|
||||||
"title": "[DevFrontend] État d'exécution Chrono suivant prêt",
|
"title": "[DevFrontend] État d'exécution Chrono suivant prêt",
|
||||||
"status": "open",
|
"status": "qa",
|
||||||
"priority": "medium",
|
"priority": "medium",
|
||||||
"sprint": null,
|
"sprint": null,
|
||||||
"assignedAgentIds": [
|
"assignedAgentIds": [
|
||||||
"9933c93a-b8a1-4164-a3bb-7063fdad747d"
|
"9933c93a-b8a1-4164-a3bb-7063fdad747d"
|
||||||
],
|
],
|
||||||
"updatedAt": 1784547239512
|
"updatedAt": 1784549136530
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"issueRef": "#79",
|
"issueRef": "#79",
|
||||||
|
|||||||
@ -1281,6 +1281,76 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'step chaining disabled stops at first elapsed timed boundary after kill',
|
||||||
|
() async {
|
||||||
|
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
|
||||||
|
final session = _sessionWithSnapshot(
|
||||||
|
currentProgramIndex: 0,
|
||||||
|
currentExerciseIndex: 0,
|
||||||
|
currentSetIndex: 0,
|
||||||
|
setsCount: 1,
|
||||||
|
targetReps: 1,
|
||||||
|
autoStartNextTimedStepSnapshot: false,
|
||||||
|
exerciseSteps: [
|
||||||
|
..._twoTimedSteps(),
|
||||||
|
_step(
|
||||||
|
id: 'step-3',
|
||||||
|
position: 2,
|
||||||
|
name: 'Centre',
|
||||||
|
type: ExerciseStepType.time,
|
||||||
|
defaultTargetValue: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
final repository = _FakeActiveSessionRepository()..session = session;
|
||||||
|
|
||||||
|
await ActiveExerciseStepUseCases(
|
||||||
|
sessionRepository: repository,
|
||||||
|
clock: clock,
|
||||||
|
ids: _FakeIds(),
|
||||||
|
originDeviceId: 'device-1',
|
||||||
|
).startOrResumeProgress(
|
||||||
|
sessionId: session.metadata.id,
|
||||||
|
programIndex: 0,
|
||||||
|
exerciseIndex: 0,
|
||||||
|
setIndex: 0,
|
||||||
|
);
|
||||||
|
await ActiveExerciseStepUseCases(
|
||||||
|
sessionRepository: repository,
|
||||||
|
clock: clock,
|
||||||
|
ids: _FakeIds(),
|
||||||
|
originDeviceId: 'device-1',
|
||||||
|
).startTimer(
|
||||||
|
sessionId: session.metadata.id,
|
||||||
|
programIndex: 0,
|
||||||
|
exerciseIndex: 0,
|
||||||
|
setIndex: 0,
|
||||||
|
);
|
||||||
|
clock.value = clock.value.add(const Duration(milliseconds: 4500));
|
||||||
|
|
||||||
|
final reconstructed = ActiveExerciseStepUseCases(
|
||||||
|
sessionRepository: repository,
|
||||||
|
clock: clock,
|
||||||
|
ids: _FakeIds(),
|
||||||
|
originDeviceId: 'device-1',
|
||||||
|
);
|
||||||
|
final view = await reconstructed.startOrResumeProgress(
|
||||||
|
sessionId: session.metadata.id,
|
||||||
|
programIndex: 0,
|
||||||
|
exerciseIndex: 0,
|
||||||
|
setIndex: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(view.state.status, ActiveExerciseStepProgressStatus.stoppedTimer);
|
||||||
|
expect(view.state.currentStepIndex, 1);
|
||||||
|
expect(view.state.startedAt, isNull);
|
||||||
|
expect(view.state.accumulatedMs, 0);
|
||||||
|
expect(repository.stepResults, hasLength(1));
|
||||||
|
expect(repository.stepResults.single.stepIndex, 0);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'step chaining resolution uses program override before exercise snapshot',
|
'step chaining resolution uses program override before exercise snapshot',
|
||||||
() async {
|
() async {
|
||||||
|
|||||||
Reference in New Issue
Block a user