diff --git a/1-docs/0-mng/review-2026-10-17.md b/1-docs/0-mng/review-2026-10-17.md new file mode 100644 index 0000000..0b8971e --- /dev/null +++ b/1-docs/0-mng/review-2026-10-17.md @@ -0,0 +1,214 @@ +# Ревью документации от 2026-10-17 — задания к исполнению + +> **Исполнитель:** агент сопровождения документации WatchBody. +> **Источник:** архитектурная проверка документации шагов 1–6 на соответствие +> канону std1 (`I:\Kit\Kit.DevAi\std1`: процесс `_process\process.md`, правила +> `_rules\d\d-db.md`, `d-dev.md`, `d-req.md`, `d-drg.md`, `_rules\glossary.md`) +> и исходной задаче (`Техническое задание.md`, `Требование.md`, документы +> «Метрики…», «Архитектура LLM…», «Форматы…»). +> **Состояние репозитория на момент проверки:** коммит `0554f17`, все ссылки +> на строки даны по нему; после правок ориентироваться по разделам, а не строкам. +> **Статусная модель заданий:** ⬜ не начато → 🔄 в работе → ✅ готово +> (утверждено владельцем). Отметки проставляются в разделе 6 по мере работы. +> **Общие правила исполнения:** +> 1. Правки вносятся новыми версиями утверждённых документов (перечень версий — +> раздел 5). Каждая новая версия — точка утверждения **Пользователь!** (d-dev-4). +> 2. Содержание утверждённых документов меняется только в объёме заданий; +> инварианты 🛡 не ослабляются; трассировка «Ф → БЦ → КУ → версия» (раздел 6 +> requirements) сохраняется. +> 3. Задания, зависящие от решений Р1–Р3 (раздел 1), не вносятся до выбора +> владельцем. Остальные можно выполнять сразу. +> 4. Код (`3-app\`, `2-db\`) не трогается — задание касается только `1-docs\` +> и корневого `readme.md`. +> 5. ~~Push не выполняется (учётные данные remote не настроены)~~ — уточнение +> исполнителя 2026-10-17: push настроен и работает (credentials в +> Credential Manager); коммиты пушатся после каждой волны. + +## 0. Сводка ревью + +Документация в целом соответствует std1 и исходной задаче: шаги 1–6 пройдены +с точками утверждения, все 9 позиций MVP ТЗ покрыты (Ф-1–Ф-9), трассировка +полная, стеки соответствуют `Требование.md`, решения LLM-дизайна и документа +метрик перенесены. Найдено: **4 существенных дефекта (P1)** — два логических +противоречия «v1-требования ↔ v1-данные», неактуальная архитектура после +изменения 1.3 и разрыв схемы синхронизации; **4 средних (P2)**; **7 мелких +(P3, гигиена)**. Позиции внедрения MVP документа метрик (п. 5) и порядок +шагов 1–3 LLM-дизайна перенесены в требования верно, кроме данных правила 1 +(см. Р1). + +## 1. Решения владельца (блокируют волну 2) + +| Код | Вопрос | Варианты | Рекомендация ревью | +|---|---|---|---| +| **Р1** | Данные правила 1 (пульс покоя +8 два дня / самочувствие ≤ 2) отсутствуют в v1: `daily_log` v1 хранит только АД и вес; `hr_resting`, `wellbeing` помечены v2 — а Ф-12.5, БЦ-6 и КУ-7 требуют их в v1 | **А:** добавить `hr_resting`, `wellbeing` в v1-дневник (2 касания ввода) — КУ-7 закрывается целиком. **Б:** правило 1 → v2 (в v1 правила 2–6), скорректировать КУ-7. **В:** прокси — хранить предстартовый пульс сидя в `daily_log` и считать тренд по нему | **А** | +| **Р2** | Идентификация клиентских сущностей: протокол sync требует `client_guid` для каждой записи, но у `exercise`, `program_version`, `athlete_profile` его нет; ключи — серверные `serial`, телефон офлайн не может узнать server id для ссылок (`workout_set.exercise_id`, `workout.program_version_id`) | **А:** добавить `client_guid UNIQUE` в эти таблицы + расширить ответ sync маппингом `{entity, client_guid, id}`. **Б:** UUID как PK всех клиентских сущностей. **В:** натуральные ключи (имя упражнения у атлета) | **А** (минимальная правка БД, идемпотентность сохраняется) | +| **Р3** | Safety-пороги применяются на телефоне офлайн (экран допуска, Ф-13.2), но определены только в серверном `appsettings.json`; канал доставки на телефон не задан | **А:** продублировать пороги в телефонном Preferences (умолчания — документ метрик); серверные `Safety.*` — для серверных правил/`red_flags`. **Б:** синхронизируемая сущность `settings` (сервер — истина; до первой синхронизации — умолчания телефона) | **А** для v1 (один владелец; расхождение источников задокументировать, общая сущность — кандидат v2) | + +Если владелец не выбрал вариант — подготовить диффы по рекомендованному и +вынести на утверждение как предложение (самовольно вариант не менять). + +## 2. Задания P1 (существенные) + +### З-1. Интеграция данных правила 1 в v1 ⬜ *(после Р1; по Р1-А)* + +1. `1-docs\1-reqs\requirements.md`: + - Ф-13.1 — дневник-минимум дополнить: пульс покоя (утро), самочувствие 1–5; + - Ф-13.6 — v2-перечень сузить до «талия, сон» (пульс покоя и самочувствие + переносятся в v1); + - Ф-12.5 — указать источник данных правила 1 (`daily_log`, тренд 2 дня). +2. `1-docs\2-db\src\tables.md`: `src.daily_log` — `hr_resting`, `wellbeing` + убрать из пометки «v2», описать как поля v1. +3. `1-docs\2-db\src\functions.md`: `daily_log_upsert` — параметры + `p_hr_resting`, `p_wellbeing`. +4. `1-docs\3-tech\tech-requirements.md`: п. 2.2 (`daily_log`) — поля v1; + чек-лист шага 7 не меняется. + +### З-2. Актуализация архитектуры под Ф-13 ⬜ + +1. `1-docs\2-arch\architecture.md`: + - шапка: источники — vision **v1.3**, requirements v1.1; версия документа → + 1.1 с примечанием «актуализация под Ф-13 (изменение vision 1.3)»; + - раздел 1.2 (телефон): в `WorkoutCore` добавить ответственность «предстартовый + допуск (пороги Safety, экран допуска) и дневник самоконтроля + (`daily_log`)»; в `TrainingUi` — экраны «Сегодня» и «Допуск»; + - раздел 2 (поток): шаг 0 перед «Тренировка» — допуск (пороги АД/пульса; + блокировка/лёгкое кардио; обход блокировки логируется); + - таблица компонентов: строка БД — добавить `daily_log` к перечню. +2. `1-docs\2-arch\hld.puml`: отразить допуск/дневник подписью в `WorkoutCore` + (без новых компонентов и связей — гранулярность схемы не меняется); + перерендерить `hld.svg` + `hld.png` навыком `std1\_skills\dgm-hld` + (`python std1\_skills\dgm-hld\render.py 1-docs\2-arch\hld.puml`), рендер + рядом с исходником (d-drg-11). +3. Утверждение — **Пользователь!** + +### З-3. Синхронизация: `client_guid` и маппинг id ⬜ *(после Р2; по Р2-А)* + +1. `1-docs\2-db\src\tables.md`: `src.exercise`, `src.program_version` — + колонка `client_guid uuid NOT NULL UNIQUE` (идемпотентность sync, Ф-7.4); + `src.athlete_profile` — upsert по `athlete_id` уже идемпотентен, решение + (без `client_guid`) зафиксировать явно в комментарии. +2. `1-docs\3-tech\tech-requirements.md`: + - п. 2.1 — ответ `POST /api/v1/sync`: помимо `accepted`, маппинг + `{entity, client_guid, id}` для созданных записей (телефон хранит + соответствие локальный id ↔ серверный); + - п. 2.2 — `exercise`, `program_version`: поле `client_guid`. +3. `1-docs\1-reqs\requirements.md`: Ф-7.2/Ф-7.3 — дополнить маппингом id + (одной формулировкой: «ответ содержит соответствие client_guid → серверный + id; телефон использует его для ссылок дочерних записей»). + +### З-4. Safety-пороги телефона ⬜ *(после Р3; по Р3-А)* + +1. `1-docs\3-tech\tech-requirements.md`, п. 4.1 (телефон): параметры + `Safety.BpCancelSys/Dias` (умолч. 150/90), `Safety.BpCardioSys/Dias` + (140/90), `Safety.RestingHrSitting` (90) с валидацией — как в п. 4.2; + примечание: умолчания из документа метрик; серверные `Safety.*` — источник + для серверных правил (`red_flags`), совпадение значений — ответственность + владельца конфигурации (ограничение v1 задокументировать, общая сущность — + кандидат v2). +2. `1-docs\1-reqs\requirements.md`: раздел 3 (телефонные настройки) — + дополнить теми же параметрами; Ф-13.5 — переформулировать: «пороги допуска + — конфигурируемые в настройках телефона; серверные `Safety.*` применяются + серверными правилами». + +## 3. Задания P2 + +### З-5. `src.workout`: уникальность `fit_file_id` и `fit_workout_id` ⬜ + +`1-docs\2-db\src\tables.md`: +- у описания поля `fit_file_id` убрать «UNIQUE» — оставить составной + `UNIQUE(athlete_id, fit_file_id)` (изоляция атлетов); +- колонку `fit_workout_id` удалить: факты пишутся в ту же строку + (`facts_json`), отдельная строка «только .fit» создаётся с собственным + `client_guid` (сервер) — ссылочная колонка не используется. + +### З-6. Sync-enum: фантом и пропуск ⬜ + +`1-docs\3-tech\tech-requirements.md`, п. 2.1: из перечня `entity` убрать +`set_note` (сущности нет ни в БД, ни в требованиях); добавить `daily_log`. +(Совместить с З-3.2 — одна правка п. 2.1.) + +### З-7. Диапазон RPE ⬜ + +Согласовать: Ф-13.3 и tech-requirements п. 2.2 — «0–10»; `tables.md` — +`CHECK (rpe BETWEEN 1 AND 10)`. Рекомендация: единый диапазон **1–10** +(RPE 0 в документе метрик не используется; голос «РПЭ N» — N 1–10): в +Ф-13.3 «тапом 1–10», в tech-requirements 2.2 — «int? 1–10». При выборе +владельцем 0–10 — правится CHECK в tables.md. + +### З-8. Грамматика Ф-1.2: команда «РПЭ N» ⬜ + +`1-docs\1-reqs\requirements.md`, Ф-1.2: добавить четвёртую команду +«РПЭ **N**» → RPE последнего подхода (N 1–10, по З-7); согласовать с Ф-13.3 +и решением ОВ-2 в tech-requirements (грамматика уже включает «РПЭ»). + +## 4. Задания P3 (гигиена) + +| Код | Задание | Где | +|---|---|---| +| З-9 | Удалить мусорную строку «io header fix»; в Ф-12 перенумеровать второй «5.» (Офлайн-режим сервера) в «6.» | requirements.md:381–384 | +| З-10 | Исправить «.gp**х**» → «.gpx» (кириллическая буква) | requirements.md:267 | +| З-11 | Шапки-источники привести к vision **v1.3**: requirements (сейчас «v1.0»), tech-requirements (сейчас «v1.2»). Для architecture — в З-2 | requirements.md:4, tech-requirements.md:4 | +| З-12 | URL репозитория: `readme.md` — `VEU/VEU.WathBody.git`, `plan.md` — `VEU/WatchBody.git`. Сверить с фактическим `git remote -v` и привести оба файла к нему (сейчас remote, вероятно, не настроен — тогда принять `VEU/WatchBody.git` и исправить опечатку «WathBody») | readme.md:3–4, plan.md:3–4 | +| З-13 | Маркер «MM» в tables.md вне словаря d-db-2 (`CRUD/SELECT/NO/CUSTOM`): оставить как есть, в комментарий строки добавить «типовой набор связи ММ — d-db-3»; о необходимости маркера «MM» сообщить владельцу std1 (вне репозитория) | src/tables.md:14 | +| З-14 | Добавить в readme БД раздел «План миграции» (требование d-db-1): создание схем `src`/`ref`, вставка значений `ref.exercise_group`, порядок применения psql-файлов из `2-db\`, версионирование миграций | 1-docs/2-db/readme.md | +| З-15 | Сообщить владельцу std1 (вне репозитория): process.md шаг 6 указывает артефакты в `1-docs\d-db\`, противореча шагу 2 того же процесса и правилу d-db-1 (`1-docs\2-db\`); проект применил верный путь | — | + +## 5. Порядок исполнения и версии + +**Волна 1 — errata, выполняется сразу (З-5–З-14 без Р-зависимостей:** +З-5, З-6, З-9, З-10, З-11, З-12, З-13, З-14**).** Правки представляются +владельцу одним диффом → утверждение → коммит +«Ревью документации: errata (Ф-12 нумерация, .gpx, версии источников, +fit_file_id, sync-enum)». Версии: requirements → 1.2 (errata), +tables.md → новая редакция (дата), tech-requirements → 1.2, 2-db readme → +новая редакция. + +**Волна 2 — после решений Р1–Р3 (З-1, З-2, З-3, З-4, З-8).** Все правки +одним пакетом «Актуализация по ревью: Ф-13 в архитектуре, данные правила 1, +client_guid/маппинг sync, Safety телефона» → рендер hld → утверждение +владельцем (одно утверждение на пакет) → коммит. Версии: requirements → 1.3, +architecture → 1.1, tech-requirements → 1.3, tables/functions → новая +редакция (число функций не меняется — меняются параметры `daily_log_upsert` +и колонки `client_guid`). + +**После каждой волны — самопроверка (раздел 7) и отметки в разделе 6.** + +## 6. Чек-лист + +| Задание | P | Зависит от | Статус | +|---|---|---|---| +| Р1–Р3 решения владельца | — | — | ⬜ | +| З-1 правило 1: данные v1 | 1 | Р1 | ⬜ | +| З-2 архитектура + hld.puml + рендер | 1 | — (текст), рендер после правок | 🔄 (2026-10-17: Ф-13+Ф-14 внесены; черновик v1.1 — на утверждении) | +| З-3 client_guid + маппинг id | 1 | Р2 | ⬜ | +| З-4 Safety-пороги телефона | 1 | Р3 | ⬜ | +| З-5 fit_file_id / fit_workout_id | 2 | — | ✅ (2026-10-17) | +| З-6 sync-enum (set_note/daily_log) | 2 | — | ✅ (2026-10-17) | +| З-7 диапазон RPE | 2 | — | ⬜ | +| З-8 грамматика «РПЭ N» | 2 | З-7 | ⬜ | +| З-9 Ф-12: «io header fix», нумерация | 3 | — | ✅ (2026-10-17) | +| З-10 .gpх → .gpx | 3 | — | ✅ (2026-10-17) | +| З-11 шапки-источники → vision v1.3 | 3 | — | ✅ (2026-10-17, сразу v1.4) | +| З-12 URL репозитория | 3 | — | ✅ (2026-10-17, remote = VEU/VEU.WathBody.git, оба файла выверены) | +| З-13 маркер «MM» + письмо std1 | 3 | — | 🔄 (комментарий добавлен; письмо std1 — вне репо) | +| З-14 план миграции в 2-db readme | 3 | — | ✅ (2026-10-17) | +| З-15 сообщение владельцу std1 о process.md | 3 | — | ⬜ | + +## 7. Самопроверка после правок + +1. **requirements.md:** трассировка раздела 6 не нарушена (каждая Ф имеет БЦ/КУ); + ссылки на ОВ актуальны; нумерация Ф-12 сплошная; «РПЭ N» есть и в Ф-1.2, + и в Ф-13.3 с одним диапазоном. +2. **architecture.md / hld.puml:** шапка ссылается на vision v1.3 и + requirements текущей версии; Ф-13 присутствует в разделах 1.2, 2 и в таблице + компонентов; рендер (`hld.svg`/`hld.png`) свежее `.puml`; стиль — d-drg-3, + палитра и легенда — d-drg-4 (жёлтый — внешнее, серый — не в v1). +3. **tables.md / functions.md:** «Набор функций» в сводной таблице ↔ строки + «Списка функций» совпадают 1:1; словарь маркеров соблюдён; составной + `UNIQUE(athlete_id, fit_file_id)` — единственное описание уникальности; + `daily_log_upsert` содержит все поля v1. +4. **tech-requirements.md:** enum `entity` = перечень п. 2.2 без фантомов; + `Safety.*` есть в 4.1 и 4.2 с согласованными умолчаниями; ответ sync + описывает маппинг id. +5. **Общее:** git-статус чистый после коммитов; в логах/доках нет секретов; + push не выполнялся. diff --git a/1-docs/1-reqs/requirements.md b/1-docs/1-reqs/requirements.md index b12d6b9..9fb4b1f 100644 --- a/1-docs/1-reqs/requirements.md +++ b/1-docs/1-reqs/requirements.md @@ -1,7 +1,7 @@ # Функциональные требования: Феникс 6X v1 > Шаг 3 процесса разработки (`std1\_process\process.md`). -> Источник: [vision.md](vision.md) (утверждён 2026-10-17, v1.0), разделы +> Источник: [vision.md](vision.md) (утверждён 2026-10-17, v1.3), разделы > 1.3 (БЦ), 1.4 (КУ), 2.1–2.4; решения опросников 4.1–4.7; ТЗ > (`..\..\Техническое задание.md`), дизайн LLM-планирования (разд. 2–3, > 6–8, 11 — шаг 1); изменение vision 1.1 (2026-10-17) — несколько @@ -263,7 +263,7 @@ Garmin штатно — Ф-2.5, Ф-2.6). Код поля данных перен результат — канонический JSON тренировки в `workout_facts` (дизайн LLM-планирования, разд. 4). 3. Fallback-импорт (`--mode import`): файлы из `Import.Dir` (.fit, .tcx, - .gpх — по документу форматов) парсятся тем же конвейером; + .gpx — по документу форматов) парсятся тем же конвейером; обработанные перемещаются в `Import.ArchiveDir`; необработанные остаются с записью в логе (код возврата 2). 4. Сопоставление факт ↔ голосовой учёт: тренировка .fit сопоставляется @@ -378,8 +378,7 @@ Garmin штатно — Ф-2.5, Ф-2.6). Код поля данных перен - боль в колене ≥ 1 два занятия подряд → предложение замены упражнения из той же группы (пара-замена из атрибутов упражнения). -io header fix -5. Офлайн-режим сервера: правила выполняются при следующем запуске +6. Офлайн-режим сервера: правила выполняются при следующем запуске `serve`/`import` — телефон при этом полнофункционален (учёт и локальные планы работают без сервера). @@ -414,6 +413,57 @@ io header fix и правила координации 7–10 — v2; контрольные тесты — v3 (документ метрик, п. 5). +### Ф-14. Перерывы и возврат в режим (телефон + сервер; изменение 2) + +Источник — документ `Перерывы_подводные_камни_и_рекомендации.md` +(МакРоберт, CDC «Staying on Track», Жижин гл. 5–6, Аттия). Модель: +`active → break → return → active`. + +1. 🛡 **Break вычисляется автоматически:** пропущены все + запланированные сессии за 4 дня подряд → программа переводится + в статус `break` (Жижин гл. 6: эффект тает с 4-го дня). Ручного + включения break нет — только расчёт. +2. **Причина запрашивается у атлета:** при срабатывании автомат + показывает вопрос «Вы пропустили тренировки — что случилось?» + с выбором типа (болезнь / отпуск / аврал-недосып / травма / + другое) и предполагаемой даты возврата; до ответа тип — + «не указана» (правила 12–14 применяются после ответа). При типе + «болезнь с температурой» — минимум 3 дня после нормальной + температуры до первой сессии (правило 12). Атлет может объявить + break заранее («уезжаю в отпуск») — запланированный простой + попадает в тот же автомат. +3. **Формула возврата** (детерминированная, коэффициент от рабочего + веса, документ перерывов разд. 3.2): + + | Простой | Коэффициент | Режим | + |---|---|---| + | 4–6 дней | 100 % | первая сессия: −1 подход, RPE-цель 5–6 | + | 7–13 дней | −10 % | 1–2 недели возврата | + | 14–27 дней | −15 % | 1 вводная неделя (техника, без отказа) | + | 28–59 дней | −25 % | 2 вводные недели | + | 60+ дней / болезнь с температурой / операция | −30…−40 % | перезапуск цикла, контроль АД первые 2 недели | + + Кардио (зона 2) возвращается со 100 % длительности сразу + (митохондриальная пластичность); силу — по формуле. +4. **Return:** при первой сессии после break создаётся новая версия + программы с формульными весами (статус `draft`, `author=rules`, + `rationale` — причина снижения); подтверждение — по Ф-12.3. 🛡 + Неизменяемость версий не нарушается. +5. **`session_kind`:** каждая тренировка помечается + `normal | return | deload | test` — снижение весов при возврате + не выглядит в истории как регресс. +6. **Домашний режим:** тип break «отпуск, зал недоступен» → + переключатель активирует заготовленный поддерживающий комплекс + (отжимания, приседания без веса, тяга резинки, планка, ходьба) + с пометкой «поддержание, не прогресс» (правило 14). +7. **Правила координации 12–17** (документ перерывов, разд. 3.3): + болезнь с температурой (12), аврал/недосып → средняя тренировка + вместо тяжёлой (13), домашний комплекс (14), break ≥ 14 дней → + ужесточение порогов АД на 2 недели (отмена при > 145/90) (15), + 2+ перерыва ≥ 7 дней за месяц → план 2 дня/нед до adherence ≥ 80 % + (16), возврат после break ≥ 14 дней → тест-сессия при RPE ≤ 6 (17). + Считает `ProgressionRules` вместе с правилами 1–11. + ### Логирование (телефон и сервер) 1. `Info`: старт/остановка тренировки, каждая команда (Ф-1.5), пакеты @@ -464,6 +514,7 @@ io header fix | Ф-13 самоконтроль и допуск | БЦ-6 | КУ-7 | v1 | | Ф-12 LLM-контур (еженедельно) | БЦ-3 | — | v2 | | Ф-13 полная телеметрия, правила 7–10 | БЦ-6 | — | v2 | +| Ф-14 перерывы и возврат | БЦ-3, БЦ-6 | КУ-6, КУ-7 | v1 | | Контрольные тесты | БЦ-6 | — | v3 | | Wake-word (Ф-1) | БЦ-1 | — | v2 | | iOS | БЦ-1, БЦ-2 | — | v2 | diff --git a/1-docs/1-reqs/vision.md b/1-docs/1-reqs/vision.md index 6b27a19..0672d86 100644 --- a/1-docs/1-reqs/vision.md +++ b/1-docs/1-reqs/vision.md @@ -1,8 +1,8 @@ # Vision: Феникс 6X — контроль силовых тренировок (телефон + Garmin Fenix 6 + личный сервер) -> Версия 1.3 — **УТВЕРЖДЕНО** (2026-10-17; вопросы опросника 4.1–4.7 +> Версия 1.4 — **УТВЕРЖДЕНО** (2026-10-17; вопросы опросника 4.1–4.7 > отвечены, ответы применены; утверждение — 2026-10-17; изменения -> 1.1–1.3 — указания пользователя от 2026-10-17). +> 1.1–1.4 — указания пользователя от 2026-10-17). > Изменение 1.1: серверная часть > поддерживает нескольких атлетов — у каждого свои программы, профиль > и данные, с собственных телефона и часов (пп. 2.2, 2.4, 3.1); @@ -23,6 +23,12 @@ > (пороги АД/пульса), RPE и боль в колене по сетам; правила > координации Ф-12 расширены 11 детерминированными правилами по книгам > (пп. 2.2, 2.3, 3.3). +> Изменение 1.4 (документ «Перерывы_подводные_камни_и_рекомендации.md», +> 2026-10-17): добавлена Ф-14 «Перерывы и возврат в режим» — автомат +> `active → break → return → active` (детекция по пропускам или метка +> пользователя), формула снижения весов по длительности простоя +> (−10 %…перезапуск цикла), метка `session_kind`, домашний +> поддерживающий комплекс, правила координации 12–17 (пп. 2.1, 2.2). > Источник идеи: техническое задание > «Феникс 6X» (Garmin Edition) от 17.10.2026 > ([Техническое задание.md](../../Техническое%20задание.md)); требование @@ -325,6 +331,15 @@ Garmin, наш продукт фиксирует результаты без р МакРоберт, CDC); состав v1 — MVP-приоритет документа (его п. 5): дневник-минимум + правила координации 1–6; утренняя телеметрия полностью и правила 7–10 — v2, контрольные тесты — v3. +- **Ф-14. Перерывы и возврат в режим** (изменение 1.4) — конечный автомат + `active → break → return → active`: break вычисляется автоматически + (пропуск всех запланированных сессий 4 дня), причина запрашивается + у атлета (болезнь/отпуск/аврал/травма); при возврате программа переводится в режим + возврата по формуле длительности простоя (100 %…−40 %, вводные + недели), создаётся новая версия с `rationale`; тренировки помечаются + `session_kind` (normal/return/deload/test); «отпуск без зала» — + домашний поддерживающий комплекс; правила координации 12–17 + (документ перерывов, разд. 3.2–3.3). ### 2.2. Объём первоначально запланированной версии @@ -332,8 +347,8 @@ Garmin, наш продукт фиксирует результаты без р **v1.0 = полный MVP-цикл ТЗ (Ф-1–Ф-9) + программы: Ф-10, Ф-11 и правила прогрессии/координации (основа Ф-12) — шаг 1 порядка внедрения LLM-планирования, без LLM; Ф-13 в MVP-составе документа метрик -(дневник-минимум, допуск по АД/пульсу, правила 1–6); LLM-контур -Ф-12 — v2**. +(дневник-минимум, допуск по АД/пульсу, правила 1–6); Ф-14 — перерывы +и возврат (изменение 1.4); LLM-контур Ф-12 — v2**. Разработка — в порядке перечня MVP ТЗ: часы → связь с телефоном → экран тренировки → голосовой ввод → локальная БД → сервер → забор .fit → синхронизация → история и веб. diff --git a/1-docs/2-arch/architecture.md b/1-docs/2-arch/architecture.md index 393208c..fa2f0af 100644 --- a/1-docs/2-arch/architecture.md +++ b/1-docs/2-arch/architecture.md @@ -26,13 +26,16 @@ vision 1.1); перечень моделей — открытый вопрос 8 ### 1.2. Телефон атлета — **Phone.WatchBody** (Android, Kotlin) - `TrainingUi` — экраны (Jetpack Compose — кандидат, фиксируется - шагом 5): активная тренировка, история, программы, профиль; - тёмная тема, крупные зоны касания. + шагом 5): активная тренировка, история, программы, профиль, + «Сегодня» (дневник) и «Допуск»; тёмная тема, крупные зоны касания. - `VoiceInput` — офлайн-STT (движок — открытый вопрос 2) + грамматика команд (Ф-1.2) + TTS-подтверждения; журнал команд для сопоставления с .fit. - `WorkoutCore` — логика тренировки и программ: подходы, таймеры, - план/факт, редактор программ; единственный писатель `LocalDb`. + план/факт, редактор программ; 🛡 предстартовый допуск (пороги + Safety, экран допуска) и дневник самоконтроля (`daily_log`); + автомат перерывов и формула возврата (Ф-14); единственный писатель + `LocalDb`. - `LocalDb` — Room/SQLite: текущая тренировка, история, программы, библиотека, профиль, очередь. - `SyncQueue` — исходящие записи с `client_guid`, пакеты ≤ 50, @@ -53,9 +56,9 @@ vision 1.1); перечень моделей — открытый вопрос 8 | `FitFetcher` | `Server.WatchBody.Fetch` | Клиент Garmin Connect (неофициальный, опросник 4.3); `--mode fetch`; дедупликация по `fit_file_id` | | `FitParser` | `Server.WatchBody.Import` | Garmin FIT SDK: Session/Lap/Record/Set → `workout_facts`; `--mode import` (fallback: .fit/.tcx/.gpx из папки) | | `MetricsEngine` | `Server.WatchBody.Core` | adherence, тоннаж по группам, 1ПМ, пульс-метрики, красные флаги (АД/пульс/боль — документ метрик) → `workout_metrics` | -| `ProgressionRules` | `Server.WatchBody.Core` | Правила прогрессии, делоада и координации 1–6 (документ метрик) → draft-версии программ (`author=rules`) | +| `ProgressionRules` | `Server.WatchBody.Core` | Правила прогрессии, делоада и координации 1–11 (документ метрик) + 12–17 перерывы (документ перерывов): детекция `break` по пропускам, формула возврата → draft-версии (`author=rules`) | | `ProgramStore` | `Server.WatchBody.Core` | Версионированный JSON программ; неизменяемость версий; `active` — ровно один на атлета | -| БД | схема `src` \| `ref` | PostgreSQL: атлеты, тренировки/факты, метрики, программы, журнал LLM (v2) | +| БД | схема `src` \| `ref` | PostgreSQL: атлеты, тренировки/факты + `session_kind`, дневник (`daily_log`), перерывы (`breaks`), метрики, программы, журнал LLM (v2) | Общая библиотека — `Kit.Helpers` (`3-app\1-lib`, std1). Взаимодействие с LLM (v2, `LlmPlanner`) — по правилам std1 `c-llm`; в v1 компонент @@ -69,6 +72,11 @@ vision 1.1); перечень моделей — открытый вопрос 8 ## 2. Поток цикла обработки +0. **Допуск и перерывы.** Перед стартом — экран допуска (АД/пульс; + красные флаги блокируют или переводят в лёгкое кардио; обход + логируется); автомат перерывов ставит `break` по пропускам и + запрашивает причину у атлета; при возврате — формульная версия + (Ф-14). 1. **Тренировка.** Атлет запускает «Силовую» на часах (`FenixDataField` показывает пульс/зоны/подходы) и активирует голосовой ввод на телефоне (`VoiceInput` → команды → `WorkoutCore` → `LocalDb`). Часы и телефон diff --git a/1-docs/2-arch/hld.png b/1-docs/2-arch/hld.png index 7468eae..f69c56c 100644 Binary files a/1-docs/2-arch/hld.png and b/1-docs/2-arch/hld.png differ diff --git a/1-docs/2-arch/hld.puml b/1-docs/2-arch/hld.puml index 1d83d6a..c7a56fe 100644 --- a/1-docs/2-arch/hld.puml +++ b/1-docs/2-arch/hld.puml @@ -31,7 +31,7 @@ node "Часы атлета\n(Garmin, Connect IQ)" as Watch { node "Телефон атлета\n(Android, Kotlin)" as Phone { component "VoiceInput\nофлайн-STT + грамматика команд" as VoiceInput component "TrainingUi\nэкран тренировки, таймеры, история" as TrainingUi - component "WorkoutCore\nлогика тренировки и программ" as WorkoutCore + component "WorkoutCore\nлогика тренировки, допуск,\nдневник, перерывы" as WorkoutCore component "LocalDb\nRoom/SQLite" as LocalDb component "SyncQueue\nочередь + идемпотентность" as SyncQueue component "WatchChannel\ncompanion-канал Connect IQ" as WatchChannel diff --git a/1-docs/2-arch/hld.svg b/1-docs/2-arch/hld.svg index e078aef..032a84f 100644 --- a/1-docs/2-arch/hld.svg +++ b/1-docs/2-arch/hld.svg @@ -1 +1 @@ -Феникс 6X: часы + телефон атлета + личный сервер(v1.0; серым — v2, жёлтым — внешние системы)Часы атлета(Garmin, Connect IQ)Телефон атлета(Android, Kotlin)Личный сервер(C# / .NET 10)WebAppASP.NET CoreFitPipelineзабор и парсингFenixDataFieldполе данных «Феникс»:пульс, зоны, подходы, виброVoiceInputофлайн-STT + грамматика командTrainingUiэкран тренировки, таймеры, историяWorkoutCoreлогика тренировки и программLocalDbRoom/SQLiteSyncQueueочередь + идемпотентностьWatchChannelcompanion-канал Connect IQMetricsEngineadherence, тоннаж, 1ПМProgressionRulesправила прогрессии → draftProgramStoreверсии программ (JSON)PostgreSQLслои src | refRestApisync, workouts, programs(X-Api-Key атлета)AdminWebконсоль владельца(логин/пароль)FitFetcherклиент Garmin Connect(+ папка импорта)FitParserGarmin FIT SDKLlmPlannerеженедельный контур LLMGarmin Connect(облако, .fit)Инвариант: часы автономны — запись .fit ведётплатформа Garmin, поле — только отображение.Один код поля — сборки под модели Garmin.Инвариант офлайн-first: все данные сначала в LocalDb;сеть — только SyncQueue. Каждой записи — client_guid.Инвариант изоляции атлетов: ключ → athlete_id,все выборки — по атлету.пульс, зоны,таймер отдыхаlive-данные(если связь есть)командыHTTPSPOST /sync.fit по расписаниюworkout_factsdraft-версияактивнаяверсиясводка недели(v2)предложение(v2)СвязьЗначение A -> B A зависит от / использует B A ..> B связь версии v2 (в v1 не реализована) жёлтый внешняя система серый задумано, не в v1 \ No newline at end of file +Феникс 6X: часы + телефон атлета + личный сервер(v1.0; серым — v2, жёлтым — внешние системы)Часы атлета(Garmin, Connect IQ)Телефон атлета(Android, Kotlin)Личный сервер(C# / .NET 10)WebAppASP.NET CoreFitPipelineзабор и парсингFenixDataFieldполе данных «Феникс»:пульс, зоны, подходы, виброVoiceInputофлайн-STT + грамматика командTrainingUiэкран тренировки, таймеры, историяWorkoutCoreлогика тренировки, допуск,дневник, перерывыLocalDbRoom/SQLiteSyncQueueочередь + идемпотентностьWatchChannelcompanion-канал Connect IQMetricsEngineadherence, тоннаж, 1ПМProgressionRulesправила прогрессии → draftProgramStoreверсии программ (JSON)PostgreSQLслои src | refRestApisync, workouts, programs(X-Api-Key атлета)AdminWebконсоль владельца(логин/пароль)FitFetcherклиент Garmin Connect(+ папка импорта)FitParserGarmin FIT SDKLlmPlannerеженедельный контур LLMGarmin Connect(облако, .fit)Инвариант: часы автономны — запись .fit ведётплатформа Garmin, поле — только отображение.Один код поля — сборки под модели Garmin.Инвариант офлайн-first: все данные сначала в LocalDb;сеть — только SyncQueue. Каждой записи — client_guid.Инвариант изоляции атлетов: ключ → athlete_id,все выборки — по атлету.пульс, зоны,таймер отдыхаlive-данные(если связь есть)командыHTTPSPOST /sync.fit по расписаниюworkout_factsdraft-версияактивнаяверсиясводка недели(v2)предложение(v2)СвязьЗначение A -> B A зависит от / использует B A ..> B связь версии v2 (в v1 не реализована) жёлтый внешняя система серый задумано, не в v1 \ No newline at end of file diff --git a/1-docs/2-db/readme.md b/1-docs/2-db/readme.md index 1fc1c19..cf66e4c 100644 --- a/1-docs/2-db/readme.md +++ b/1-docs/2-db/readme.md @@ -28,6 +28,24 @@ | [src\tables.md](src/tables.md) | таблицы слоя `src` | | `{слой}\functions.md` | списки функций (после утверждения таблиц) | +## План миграции (d-db-1) + +1. Схемы: `CREATE SCHEMA IF NOT EXISTS src; CREATE SCHEMA IF NOT EXISTS ref;` +2. Справочники: `ref\exercise_group.psql` — таблица + вставка 5 значений + (идемпотентно, `ON CONFLICT (code) DO NOTHING`). +3. Таблицы `src`: порядок — `athlete` → `athlete_profile` → `exercise` → + `exercise_replacement` → `program` → `program_version` → `workout` → + `workout_set` → `command_log` → `daily_log` → `workout_metrics` → + `breaks` (FK-зависимости). +4. Функции: файлы `{слой}\функции.psql` по сущностям в том же порядке + (`CREATE OR REPLACE` — перезапуск безопасен). +5. Версионирование: каталог `2-db\migrations\` — `NNN_описание.sql` + по возрастанию; каждая миграция идемпотентна (IF NOT EXISTS / + OR REPLACE); факт применения — одна запись на файл в + `src.migration` (id, filename, applied_at). +6. Сборка: скрипт `2-dbuild.ps1` применяет миграции по номеру + (утилита `Server.WatchBody.Import --mode migrate`). + ## Таблица `llm_calls` (v2) Журнал вызовов LLM-планировщика (дизайн LLM-планирования, разд. 8) diff --git a/1-docs/2-db/src/functions.md b/1-docs/2-db/src/functions.md index 69458ce..51f491e 100644 --- a/1-docs/2-db/src/functions.md +++ b/1-docs/2-db/src/functions.md @@ -7,6 +7,10 @@ > они для сервисов владельца): изоляция атлетов. > Статусы: `PLAN` — только в списке (спецификаций и кода нет). > **УТВЕРЖДЕНО** (2026-10-17) — список функций к реализации утверждён. +> Новая редакция (2026-10-17): + `breaks` (break_insert/update/select), +> `session_kind` в workout_insert/update — интеграция документа +> перерывов (Ф-14, изменение vision 1.4). Утверждение добавки — +> Пользователь! ## Список функций @@ -32,8 +36,8 @@ | program_version | program_version_update | PLAN | p_athlete_id, p_id, p_status | int — число строк | - | - | 🛡 меняется только статус; переходы draft→active→archived; активной становится ровно одна (сдвиг прежней в archived) | | program_version | program_version_select | PLAN | p_athlete_id, p_program_id, p_status, p_author | TABLE — строки (без body) | - | - | body — отдельным get (крупный jsonb) | | program_version | program_version_get | PLAN | p_athlete_id, p_id | TABLE — одна строка с body | - | - | — | -| workout | workout_insert | PLAN | p_athlete_id, p_client_guid, p_program_version_id, p_started_at | int — id | - | - | повтор `client_guid` возвращает существующий id (🛡 идемпотентность) | -| workout | workout_update | PLAN | p_athlete_id, p_id, p_ended_at, p_status, p_avg_hr, p_fit_workout_id, p_facts_json, p_fit_file_id, p_hr_recovery_s | int — число строк | - | - | факты .fit дописывает FitParser; клиент — только ended/status/avg_hr | +| workout | workout_insert | PLAN | p_athlete_id, p_client_guid, p_program_version_id, p_started_at, p_session_kind | int — id | - | - | повтор `client_guid` возвращает существующий id (🛡 идемпотентность) | +| workout | workout_update | PLAN | p_athlete_id, p_id, p_ended_at, p_status, p_session_kind, p_avg_hr, p_facts_json, p_fit_file_id, p_hr_recovery_s | int — число строк | - | - | факты .fit дописывает FitParser; клиент — только ended/status/session_kind/avg_hr | | workout | workout_select | PLAN | p_athlete_id, p_status, p_date_from, p_date_to | TABLE — карточки + подходы (агрегат jsonb) | - | - | мультикурсор/агрегат: карточка + sets (d-db-6) | | workout | workout_get | PLAN | p_athlete_id, p_id | TABLE — одна строка + sets + command_log | - | - | полная карточка (Ф-9.2) | | workout_set | workout_set_insert | PLAN | p_athlete_id, p_client_guid, p_workout_id, p_exercise_id, p_seq, p_weight_kg, p_reps, p_done_at, p_source, p_in_plan, p_rpe, p_knee_pain | int — id | - | - | идемпотентность по client_guid | @@ -44,3 +48,6 @@ | daily_log | daily_log_select | PLAN | p_athlete_id, p_date_from, p_date_to | TABLE — строки | - | - | для сводки метрик и AdminWeb | | workout_metrics | workout_metrics_upsert | PLAN | p_athlete_id, p_workout_id, p_adherence, p_tonnage, p_tonnage_by_group, p_e1pm_by_exercise, p_hr_metrics, p_red_flags | int — id | - | - | 1:1, пересчёт MetricsEngine | | workout_metrics | workout_metrics_select | PLAN | p_athlete_id, p_workout_id, p_date_from, p_date_to | TABLE — строки | - | - | графики AdminWeb (Ф-9.4) | +| breaks | break_insert | PLAN | p_athlete_id, p_client_guid, p_kind, p_source, p_started_on, p_note | int — id | - | - | auto-ставит сервер по пропускам; manual — телефон | +| breaks | break_update | PLAN | p_athlete_id, p_id, p_ended_on | int — число строк | - | - | закрытие break первой сессией после возврата | +| breaks | break_select | PLAN | p_athlete_id, p_kind, p_date_from, p_date_to | TABLE — строки | - | - | журнал перерывов; CSV-выгрузка (документ перерывов разд. 4) | diff --git a/1-docs/2-db/src/tables.md b/1-docs/2-db/src/tables.md index 7dde977..8be538b 100644 --- a/1-docs/2-db/src/tables.md +++ b/1-docs/2-db/src/tables.md @@ -11,7 +11,7 @@ | `src.athlete` | сущность | athlete_insert, athlete_update, athlete_select, athlete_get | CUSTOM | без `_delete`: блокировка вместо удаления (`is_blocked`); запись/чтение — владелец и сервисы сервера, не атлет | | `src.athlete_profile` | сущность | athlete_profile_upsert, athlete_profile_get | CUSTOM | 1:1 к `athlete`; upsert вместо insert/update (одна запись) | | `src.exercise` | сущность | exercise_insert, exercise_update, exercise_delete, exercise_select, exercise_get | CRUD | `_delete` — логический (`is_active=0`, requirements Ф-4.2); функции фильтруют `is_active` по умолчанию | -| `src.exercise_replacement` | связь ММ | exercise_replacement_insert, exercise_replacement_delete | MM | пара-замена для правила 6 (документ метрик); выборка — внутри `exercise_select` | +| `src.exercise_replacement` | связь ММ | exercise_replacement_insert, exercise_replacement_delete | MM | типовой набор связи ММ — d-db-3; пара-замена для правила 6 (документ метрик); выборка — внутри `exercise_select` | | `src.program` | сущность | program_insert, program_select, program_get | CUSTOM | контейнер версий; без update/delete — жизненный цикл ведут версии | | `src.program_version` | сущность | program_version_insert, program_version_update, program_version_select, program_version_get | CRUD | `body` jsonb (схема дизайна LLM-планирования разд. 2); 🛡 неизменяемость: `_update` меняет только `status` | | `src.workout` | сущность | workout_insert, workout_update, workout_select, workout_get | CRUD | `client_guid` UNIQUE — идемпотентность; `facts_json` — факты .fit | @@ -19,6 +19,7 @@ | `src.command_log` | сущность | command_log_insert, command_log_select | CUSTOM | журнал голосовых команд (Ф-1.5, 🛡 не редактируется); update/delete нет | | `src.daily_log` | сущность | daily_log_upsert, daily_log_select | CUSTOM | день уникален для атлета (`UNIQUE(athlete_id, date)`) — upsert | | `src.workout_metrics` | сущность | workout_metrics_upsert, workout_metrics_select | CUSTOM | 1:1 к `workout`, считает сервер (MetricsEngine) — телефон только читает; upsert (пересчёт) | +| `src.breaks` | сущность | break_insert, break_update, break_select | CUSTOM | перерывы (Ф-14); закрытие = update (`ended_at`); delete нет — журнал | ## Описания @@ -99,13 +100,13 @@ | `started_at` | timestamptz NOT NULL | начало (UTC) | | `ended_at` | timestamptz NULL | конец | | `status` | text NOT NULL DEFAULT 'active' | `active` \| `finished` \| `cancelled` (Ф-3.5) | +| `session_kind` | text NOT NULL DEFAULT 'normal' | `normal` \| `return` \| `deload` \| `test` — интерпретация снижения весов (Ф-14.5) | | `avg_hr` | int NULL | средний пульс | -| `fit_workout_id` | int NULL | сопоставленная тренировка .fit — см. ниже | | `facts_json` | jsonb NULL | канонический факт из .fit (`workout-facts/1`, tech-requirements 2.3); заполняет FitParser | -| `fit_file_id` | text NULL UNIQUE | дедупликация fetch (Ф-8.1) | +| `fit_file_id` | text NULL | дедупликация fetch (Ф-8.1); уникальность — составная `UNIQUE(athlete_id, fit_file_id)` | | `hr_recovery_s` | int NULL | возврат пульса к <90 (Ф-13.4, из .fit) | -`UNIQUE(athlete_id, fit_file_id)`; сопоставление телефон ↔ .fit — окно +`UNIQUE(athlete_id, fit_file_id)` — единственная уникальность `fit_file_id`; сопоставление телефон ↔ .fit — окно ±15 минут по `started_at` (Ф-8.4): факты пишутся в ту же строку (`facts_json`), либо создается строка «только .fit» без `client_guid` пары — тогда `client_guid` генерирует сервер. @@ -156,6 +157,19 @@ | `wellbeing` | int NULL CHECK (1–5) | самочувствие (v2) | | `client_guid` | uuid NOT NULL UNIQUE | идемпотентность | +### `src.breaks` — перерывы (Ф-14) + +| Поле | Тип | Описание | +|---|---|---| +| `id` | serial PK | — | +| `athlete_id` | int NOT NULL | → `src.athlete.id` | +| `kind` | text NULL | ответ атлета: `illness` \| `vacation` \| `workload` \| `injury` \| `other`; NULL — ещё не отвечен (правила 12–14 ждут ответа) | +| `source` | text NOT NULL DEFAULT 'auto' | 🛡 всегда `auto` — break вычисляется по пропускам (Ф-14.1) | +| `started_on` | date NOT NULL | первый пропущенный день | +| `ended_on` | date NULL | возврат (заполняется первой сессией после break) | +| `note` | text | причина-текст пользователя | +| `client_guid` | uuid NOT NULL UNIQUE | идемпотентность (для manual) | + ### `src.workout_metrics` — метрики тренировки (MetricsEngine, 1:1) | Поле | Тип | Описание | diff --git a/1-docs/3-tech/tech-requirements.md b/1-docs/3-tech/tech-requirements.md index b458c5f..743e6e5 100644 --- a/1-docs/3-tech/tech-requirements.md +++ b/1-docs/3-tech/tech-requirements.md @@ -1,12 +1,15 @@ # Технические требования: WatchBody («Феникс 6X») v1 > Шаг 5 процесса разработки (`std1\_process\process.md`). -> Источники: [vision.md](../1-reqs/vision.md) v1.2, +> Источники: [vision.md](../1-reqs/vision.md) v1.4, > [requirements.md](../1-reqs/requirements.md) (утверждён, раздел 7 — > открытые вопросы), [architecture.md](../2-arch/architecture.md) > (утверждена), дизайн LLM-планирования, документ форматов. > Версия 1.1 — **УТВЕРЖДЕНО** (2026-10-17; интеграция документа метрик — > Ф-13, Safety-пороги, daily_log — утверждена вместе с документом). +> Версия 1.2 — черновик (2026-10-17): errata ревью (З-6, З-11) + +> интеграция документа перерывов (Ф-14: сущность `break`, +> `session_kind`). Утверждение — Пользователь! ## 1. Решения открытых вопросов (закрытие раздела 7 requirements) @@ -31,7 +34,7 @@ ```json { "client_guid": "uuid-v4", - "entity": "workout | exercise | program_version | profile | workout_set | set_note", + "entity": "workout | workout_set | exercise | program_version | profile | daily_log | break", "op": "upsert", "data": { ...схема сущности... } } @@ -47,12 +50,16 @@ - `exercise`: `exercise_id` (uuid), `name`, `group` (push|pull|legs|core|…), `is_base` (bool), `is_active` (bool); - `workout`: `workout_id` (uuid), `started_at`/`ended_at` (UTC ISO 8601), - `status` (active|finished|cancelled), `program_version_id` (nullable), + `status` (active|finished|cancelled), `session_kind` + (normal|return|deload|test — Ф-14.5), `program_version_id` (nullable), `avg_hr`; - `workout_set`: `workout_id`, `exercise_id`, `seq`, `weight_kg`, `reps`, `done_at`, `source` (voice|watch|edit), `in_plan` (bool), `rpe` (int? 0–10), `knee_pain` (int? 0–10, только группа «ноги»); - `profile`: `sex`, `birth_year`, `weight_kg`, `hr_max` (nullable); +- `break`: `kind` (NULL до ответа атлета), `started_on`, `note`, + `planned_return` — break ставится автоматически (детекция по + пропускам ≥ 4 дней), причина запрашивается у атлета (Ф-14.1–2); - `daily_log`: `date` (YYYY-MM-DD), `bp_sys`, `bp_dias`, `weight_kg` (Ф-13.1; v2 добавит `hr_resting`, `waist_cm`, `sleep_h`, `wellbeing`); - `program_version`: JSON-схема программы из дизайна LLM-планирования diff --git a/Перерывы_подводные_камни_и_рекомендации.md b/Перерывы_подводные_камни_и_рекомендации.md new file mode 100644 index 0000000..66ef51d --- /dev/null +++ b/Перерывы_подводные_камни_и_рекомендации.md @@ -0,0 +1,93 @@ +# Перерывы в тренировках и «подводные камни»: правила из книг + рекомендации для программного комплекса + +> Дата: 2026-10-17. Источники: МакРоберт «Думай! 2» (циклирование, болезнь, авралы), CDC/Tufts «Growing Stronger» (гл. «Staying on Track»: отпуск/болезнь/срывы), Жижин (гл. 5–6: перерывы, переутомление), Аттия «Пережить» (обратимость адаптации), «10 ошибок начинающих». +> Связано: `program-trenirovok.json` (v4), `Метрики_тренировок_и_самоконтроля.md`, `Архитектура_LLM_планирования_тренировок.md`. + +## 1. Что говорят книги о простоях + +| Ситуация | Правило | Источник | +|---|---|---| +| Перерыв **4+ дня** между тренировками | «сводит тренировочный эффект к нулю» — нельзя допускать регулярно | Жижин гл. 6 | +| Простуда (1–2 пропущенные тренировки) | Пропустить; при возврате **сбросить 5–10 кг** со штанги, 1–2 недели на возврат к прежним весам. Но если силы сохранились — можно продолжить с прежними: «опыт подскажет» | МакРоберт, гл. о циклах | +| Аврал на работе, недосып, пропущенная неделя | Возобновить **с меньшими весами**, 2 недели на возврат к прежнему уровню | МакРоберт | +| Плановый отдых между циклами | 7–10 дней; после — «фаза разгона»: веса **−10–15%** от освоенных, упор на технику, 1–2 «вводные» недели | МакРоберт (также «Руки титана»: 10-дневные паузы между фазами) | +| Отпуск/болезнь/семья/работа — **1–2+ недели** | «Не чувствовать вины. Вернуться к тренировкам как можно быстрее. Вернуться туда же, где остановился, **может и не получиться — чуть снизить веса**. Потерянное вернётся» | CDC «Staying on Track» | +| Врач запретил нагрузки (болезнь/операция) | Тренировки не начинать до разрешения (PAR-Q — входной скрининг) | CDC (PAR-Q) | +| Митохондриальная форма (зона 2) | «Не используете — теряете», но митохондрии пластичны: регулярный возврат восстанавливает их быстрее, чем набиралось с нуля | Аттия гл. 10 | +| Регулярность как принцип | «Тренироваться ровно и стабильно, без перерывов» — но жизнь вносит перерывы, поэтому их надо **циклировать по науке**, а не героически пересиливать | МакРоберт | + +**Вывод из книг:** перерыв — это не провал, а штатная часть цикла. Система координации должна не «прощать» пропуски, а **автоматически переводить программу в режим возврата** с заведомо заниженными весами. + +## 2. Смежные «подводные камни» (из тех же книг) + +1. **Перетренированность** (Жижин гл. 5–6; МакРоберт): ухудшение настроения, раздражительность, сбитый сон, нежелание тренироваться, утренний пульс +8–10, застой результатов. Лечение — не «пробить», а отдых/лёгкая неделя. У 45+ с гипертонией перетр = прямая угроза АД. +2. **Застой (плато)** (МакРоберт): не добавлять упражнения, а менять число рабочих сетов (1↔2↔3), пересмотреть отдых/сон/еду, при необходимости — полный перерыв на неделю и новый цикл. +3. **Недосып и стресс на работе** (МакРоберт): «нет смысла тренироваться тяжело, если вас преследуют стрессы» — тяжёлая тренировка при <7 ч сна урезается по интенсивности. +4. **Тренировка через боль** («10 ошибок» №4; Шварценеггер кн. 5): острая боль = стоп; боль, проходящая после разминки, — тоже сигнал; колено: 2 занятия подряд с болью → замена упражнения. +_Психологические эффекты (чувство вины после пропуска, «растерянность» после возврата) — осознаваемы пользователем и в автоматическую координацию не тащим; учитываются только в тоне сообщений UI. Ниже — измеримые проблемы._ + +5. **Возврат «с места в карьер»** (МакРоберт, CDC): типовая травма возвращенца — старт с прежних весов после 2+ недель пропуска. Измеримо: `break_days ≥14` → формульное снижение весов (раздел 3.2). +6. **Праздники/отпуск = еда** (Аттия, Жижин гл. 7): вес за отпуск уходит вверх. Измеримо: тренд веса тела — корректируется дефицит по правилу 8–9 из файла метрик. +7. **Длительная мышечная боль** (МакРоберт): боль дольше недели. Измеримо: флаг боли ≥1 два занятия подряд → облегчённая вторая тренировка (60–70%, 2–3 сета). +8. **Замена упражнений при отсутствии зала** (командировка, отпуск): измеримо по метке типа break = vacation/no_gym → домашний поддерживающий комплекс с ожиданием «поддержание, не прогресс» (Жижин). + +## 3. Рекомендации для программного комплекса «Феникс 6X» + +### 3.1. Модель состояний пользователя + +Ввести конечный автомат поверх программы: `active → break → return → active`. + +- **`break`** — ставится автоматически: пропущены все запланированные сессии за N дней (N = 4 по Жижину для «эффект начинает таять»; 10–14 дней — «полноценный простой»), либо вручную пользователем («болею», «отпуск», «аврал», «травма») с указанием типа и предполагаемой даты возврата. +- **`return`** — при первой сессии после break; программа на 1–2 недели (или по формуле ниже) переводится в режим возврата. + +### 3.2. Формула снижения при возврате (детерминированная, для валидатора) + +`коэффициент весов = f(дней простоя)`, от рабочего веса: + +| Простой | Коэффициент | Комментарий | +|---|---|---| +| 4–6 дней | 100%, но первая сессия −1 подход в упражнении и −RPE (цель 5–6) | «опыт подскажет»: если всё легко — сразу к прежним (МакРоберт) | +| 7–13 дней | −10% | простойуд + простуда-граница (МакРоберт: −5–10 кг ≈ −10%) | +| 14–27 дней | −15%, и 1 неделя «вводная» (техника, без отказа) | «фаза разгона» МакРоберта | +| 28–59 дней | −25%, 2 вводные недели | консервативная экстраполяция + CDC «снизить веса» | +| 60+ дней / после болезни с температурой / после операции | перезапуск цикла: −30…−40%, возврат к вводному комплексу месяца 1, обязательный контроль АД первые 2 недели | новый цикл (МакРоберт), CDC: «restart slowly» | + +Отдельно: **кардио-зона 2 восстанавливается быстрее силы** (Аттия, митохондриальная пластичность) — возвращать кардио можно с 100% длительности сразу, силу — по формуле. + +### 3.3. Правила координации (добавка к 11 правилам из файла метрик) + +12. `тип break = болезнь с температурой` → минимум 3 полных дня после нормальной температуры до первой сессии; первая сессия — 50% объёма. +13. `тип break = аврал/недосып` (без пропуска всех сессий) → на этой неделе вместо «большой» тренировки ставится «средняя»: тяжёлые подходы −1, RPE-цель −1 (МакРоберт). +14. `тип break = отпуск с залом недоступен` → выдаётся домашний поддерживающий комплекс (отжимания, приседания без веса/до стула, тяга резинки, планка, ходьба) с пометкой «поддержание, не прогресс» (Жижин: домашний тренинг слабее — ожидания занижаем). +15. `break ≥14 дней` → при возврате контрольные пороги АД ужесточаются на 2 недели (отмена при >145/90 вместо 150/90) — возврат после простоя при гипертонии контролируем строже (Жижин гл. 3). +16. `2+ перерыва ≥7 дней за месяц` → план сокращается структурно: 2 дня/нед вместо 3 (CDC: устойчивость важнее объёма), пока adherence не вернётся к 80%+. +17. `возврат после break ≥14 дней` → тест-сессия: работаем по RPE ≤6, вес = формула, по факту пульса/АД решение о следующей. + +### 3.4. UX-рекомендации + +- При отметке «болею/отпуск» — сразу показать рассчитанный план возврата (тип, дата, коэффициент весов). +- После break в `rationale` новой версии программы фиксируется причина снижения (журнал изменений) — это же получает LLM-планировщик в сводке. +- «Домашний режим» — заготовленный мини-план, активируется одним переключателем. +- Возврат после травмы (мениск!) — через чек-лист боли (0–10 по упражнениям с ногами) на первой тест-сессии. + +### 3.5. Что фиксировать в БД + +- Таблица `breaks`: тип (illness/vacation/workload/injury/manual), дата начала/конца, источник (auto/manual), причина-текст. +- В `sessions` — флаг `session_kind: normal | return | deload | test`, чтобы история весов интерпретировалась правильно (снижение при возврате ≠ регресс). +- Связь выполненных сессий с версией программы остаётся (архитектура), но при `return` создаётся **новая версия** программы с формульными весами — неизменяемость версий не нарушается. + +## 4. Возможности форматов планов: где это живёт + +| Формат | Поддержка простоев/возврата | Вывод | +|---|---|---| +| **Свой JSON программы** (`program-trenirovok.json`) | **Полная.** Поля: `status: break/return` у версии, `session_kind: normal/return/deload/test` у сессии, `weight_factor` у SetPlan, таблица `breaks` в БД. Коэффициенты возврата (3.2) — просто SetPlan с пересчитанными весами в новой версии: неизменяемость версий не нарушается | Основное место логики | +| **FIT (activity)** — запись тренировки | Понятия «перерыв» нет: файл = одна выполненная активность. Метка `return`/`deload` — в имени/notes сессии; факт привязывается к `program_version` на сервере | Хранит факт, не план | +| **FIT (workout)** — план на часы | Один файл = одна тренировка (шаги/повторы/отдых). Расписание недель держит Garmin Connect, но «неделя возврата −15%» не выражается — только готовые workout-файлы с уже пересчитанными весами в шагах | Экспорт сессии `return` возможен: вес зашит в шаги; семантика «это возврат» остаётся в JSON | +| **ZWO / ERG / MRC** | Только интервальные шаги мощность/пульс; силовых данных и циклирования нет | Не подходит | +| **CSV (отчёты)** | Выгрузка журнала `breaks` + adherence | Отчётность | + +**Итог:** вся логика простоев — сущность прикладного слоя (JSON + БД + валидатор). Внешние форматы получают только следствие — конкретную сессию с пересчитанными весами; это соответствует п. 5.3 «Форматы_тренировок_и_рекомендации.md» (внутренний формат — JSON, FIT — канал доставки на Garmin). + +## 5. Резюме одной строкой + +Простой — штатная фаза цикла: система сама детектирует его по пропускам или меткам пользователя, сама считает сниженные веса по длительности простоя (−10%…перезапуск), сама ужесточает контроль АД на возврате; логика живёт в собственном JSON и БД, в форматы Garmin уходит уже готовая сессия.