VEU.WathBody/1-docs/4-modules/m05-progression-rules/api_specs/04-breaks.md

69 lines
4.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Спецификация 04: перерывы — BreakEngine (Ф-14, документ перерывов 3.1–3.3)
## 1. Сигнатуры
```csharp
public bool DetectBreak(int athleteId, DateOnly today); // true — break открыт
public ProgramVersion? CloseOnReturn(int athleteId, Guid workoutId, DateOnly today);
```
(`today` — явный параметр для тестируемости; sync передаёт текущую
дату UTC. `CloseOnReturn` сам читает тренировку по id — в sync есть
только идентификатор.)
Вызов из sync (spec 05): `DetectBreak` — до записи пакета не нужен;
вызывается после коммита пакета вместе с правилами. `CloseOnReturn` —
когда пакет содержит `workout` (первая сессия после break).
## 2. DetectBreak — авто-детект (Ф-14.1)
1. Открытый break есть (`BreakRepository.Select`, `ended_on = NULL`,
последний по `started_on`) → false.
2. Активной версии нет → false.
3. Окно `[today − MissDaysForBreak + 1 .. today]` (умолчание 4 дня).
Плановые дни недели в окне — по `body.weeks[].sessions[].day`
(v1 все недели одинаковы). День плановый и по нему нет тренировки
(`workout` с датой `started_at::date` = день) — пропуск.
4. Пропущены **все** плановые дни окна → `BreakRepository.Insert`
(source=`auto`, kind=NULL, started_on = первый пропущенный день,
note «авто: пропущены все сессии за N дней»). → true.
5. Есть хотя бы одна тренировка в окне → false.
Атлет может объявить break заранее — телефон вставляет
source=`manual` (m09); авто-детект видит открытый manual и не дублирует.
## 3. CloseOnReturn — закрытие и формула возврата (Ф-14.3–14.5, правило 17)
Первый `workout` в пакете при открытом break:
1. `break_update`: `ended_on` = дата тренировки (kind/note не трогаем
— ответ атлета придёт отдельным каналом, m08/m09).
2. Длительность простоя `days = ended_on − started_on`; коэффициент
по таблице документа перерывов (разд. 3.2), фактор зажат конфигом
`[ReturnMinFactor; ReturnMaxFactor]`:
| Простой | Коэффициент | Режим |
|---|---|---|
| kind=illness (любой длительности) | 0.6 (нижняя граница) | перезапуск, rationale «болезнь» |
| 4–6 дней | 1.0 (веса без снижения) | первая сессия: подходы −1, target_rpe 5 |
| 7–13 | 0.9 | возврат 1–2 недели |
| 14–27 | 0.85 | 1 вводная неделя |
| 28–59 | 0.75 | 2 вводные недели |
| 60+ | ReturnMinFactor (0.6) | перезапуск цикла |
3. Draft-версия возврата (одна на break; повторный вызов того же
break — дедупликация по rules-draft на активную версию, как в
spec 02/03): deep-copy body, week 1:
- веса `× коэффициент`, округление к 0.5 кг; вес `null` не трогаем;
- `session_kind`: `days < 14` → `"return"`, `days ≥ 14` → `"test"`
(правило 17), для illness → `"return"`;
- simple 4–6 дней: подходы `−1` (мин 1), `target_rpe` = 5;
- `cardio_after_min` не меняется (кардио возвращается со 100 %,
Аттия);
- rationale — «возврат после break N дней (тип T): веса ×K».
4. `SessionKinds` (domain Workout) — константы normal/return/deload/test;
в body week 1 sessions пишется `"session_kind"`; телефон при старте
тренировки проставит `workout.session_kind` из активной версии.
🛡 Версии неизменяемы; активация — только человеком (Ф-14.4).