VEU.WathBody/1-docs/1-reqs/requirements.md

56 KiB
Raw Permalink Blame History

Функциональные требования: Феникс 6X v1

Шаг 3 процесса разработки (std1\_process\process.md). Источник: vision.md (утверждён 2026-10-17, v1.5), разделы 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) — несколько атлетов на сервере, разные модели часов. Версия 1.1 — УТВЕРЖДЕНО (2026-10-17; изменения vision 1.1, 1.2 учтены; утверждение — 2026-10-17). Изменение 1 (2026-10-17, указание пользователя): интегрирован документ Метрики_тренировок_и_самоконтроля.md — добавлена Ф-13, правила Ф-12 расширены (vision 1.3, БЦ-6, КУ-7). Версия 1.2 — черновик (2026-10-17): errata ревью (0-mng\review-2026-10-17.md, З-9–З-11) + интеграция документа Перерывы_подводные_камни_и_рекомендации.md — Ф-14 (изменение vision 1.4). Версия 1.3 — черновик (2026-10-17): волна 2 ревью по решениям владельца — Р1-А (пульс покоя/самочувствие в v1), Р2-Б (UUID как PK клиентских сущностей), Р3-А (Safety-пороги на телефоне); З-7 (RPE 1–10), З-8 (команда «РПЭ N»); интеграция UI/UX-рекомендаций (3-tech\ui-ux-recommendations.md). Версии 1.2, 1.3 — УТВЕРЖДЕНЫ (2026-10-17). Версия 1.4 — УТВЕРЖДЕНО (2026-10-17): ревью №2 (0-mng\review-2026-10-17-2.md) — контур break (З-17), якорь Fenix 6X (З-18, изменение vision 1.5), ОВ-10 закрыт (З-19, решение владельца), Safety.HrStrengthMax (З-20), грамматика «…с половиной» (З-26, решение владельца О-2-Б), Progression.IsoStepKg (З-27, решение владельца О-3-А), режим --mode migrate (З-25). Правки ревью №3 (0-mng\review-2026-10-17-3.md): Ф-13.7 — источник не программа (З-30), Ф-8.3 — импорт пакета программы (З-31, О-4-Б), вопрос 12.

1. Назначение и границы

Версия 1.0 реализует полный цикл «программа → тренировка без рук → архив → план/факт» (Ф-1–Ф-11, правила прогрессии Ф-12):

  • В границах: голосовой офлайн-учёт подходов на Android-телефоне; поле данных на Fenix 6X в профиле «Силовая» (пульс, зоны, Lap); офлайн-учёт с автосинхронизацией телефон ↔ сервер; забор .fit из Garmin Connect неофициальным клиентом и парсинг на сервере; REST API со статическим ключом; веб-история с CSV; программы (версионированный JSON) с контролем «план/факт» и правилами прогрессии (без LLM); поддержка нескольких атлетов на сервере — у каждого свои программы, профиль и данные (изменение vision 1.1); поддержка разных моделей часов Garmin (мультитаргет-сборка одного поля данных); самоконтроль и допуск к тренировке: дневник телеметрии, предстартовые пороги АД/пульса, RPE/боль по сетам, правила координации 1–6 (Ф-13, изменение 1).
  • Вне границ v1: LLM-планирование — еженедельный контур (v2, опросник 4.6), мезоциклы и «генератор+ревьюер» (v2.x); wake-word «Феникс, записывай» (v2, опросник 4.5); iOS (v2, опросник 4.2); экспорт FIT из приложения и доставка программ на часы (v2); трековые виды спорта — бег/вело (v3+, опросник 4.7); полная автоматическая смена программы без подтверждения (vision 2.4); саморегистрация атлетов и публичный доступ (vision 2.4, изменение 1.1); контрольные тесты (Руфье, Штанге—Генчи, тест ходьбы) и полная утренняя телеметрия с правилами 7–10 (v2/v3 — документ метрик, п. 5).

2. Состав системы, точки входа и режимы

Система — три компонента. Каждый работает автономно от остальных (vision 2.2, «независимость частей»). Клиентская часть одноатлетная (изменение vision 1.1): один телефон + одни часы принадлежат одному атлету; множество атлетов поддерживается на сервере — каждый своим API-ключом.

2.1. Часы — поле данных «Феникс» (Monkey C, Connect IQ)

Точка входа: добавление поля данных в штатный профиль «Силовая» (решение — опросник 4.1). Отдельных режимов нет: поле живёт в течение активности. Кнопки не перехватываются (Lap и Start/Stop обрабатывает Garmin штатно — Ф-2.5, Ф-2.6). Код поля данных переносимый: сборки под разные модели Garmin — конфигурациями одного проекта (разметка под размеры/разрешения экранов); перечень моделей — открытый вопрос 8. Якорное устройство — Fenix 6X (уточнение владельца 2026-10-17: в ТЗ указан Fenix 6/260×260 — описка исходника; изменение vision 1.5).

2.2. Телефон — приложение «Феникс» (Android, Kotlin)

Точка входа: значок приложения. Режимы — экраны: «Главная», «Активная тренировка», «Библиотека», «История», «Программа», «Профиль», «Настройки». Работает офлайн целиком; сеть нужна только для синхронизации (Ф-7).

2.3. Сервер — «Феникс.Server» (C# / .NET 10, PostgreSQL)

Единая точка входа: CLI --mode serve|import|fetch.

Параметр Обязательный Умолчание Семантика
--mode serve нет этот режим REST API + веб-интерфейс
--mode import нет выкл разовый импорт .fit/TCX/GPX из папки импорта и выход
--mode migrate нет выкл применение миграций из 2-db\migrations\ и выход (журнал — src.migration); коды возврата — как у import
--mode fetch нет выкл разовый забор .fit из Garmin Connect и выход (расписание — внешний планировщик, открытый вопрос 4)
--config нет appsettings.json рядом с исполняемым файлом путь к файлу настроек

Коды возврата (--mode import|fetch): 0 — успех (в т.ч. «новых файлов нет»); 1 — авария конфигурации; 2 — частичный сбой (часть файлов не обработана, детали в логе).

3. Настройки (конфигурация)

🛡 Все пути, адреса и секреты настраиваемые — не зашиты в код.

Телефон (appsettings/Preferences):

Параметр Семантика Умолчание
Server.BaseUrl адрес сервера для синхронизации — (обязательный)
Server.ApiKey статический API-ключ — (обязательный)
Sync.WifiOnly синхронизация только по Wi-Fi: 1/0 0
Hr.MaxBpm максимальная ЧСС для расчёта зон; пусто — расчёт по формуле (открытый вопрос 1) пусто
Voice.Engine офлайн-движок распознавания (фиксируется шагом 5, открытый вопрос 2) шаг 5
Voice.Language язык команд ru
Rest.DefaultSec отдых по умолчанию, если не задан командой 120
Safety.BpCancel порог отмены тренировки по АД (сист./диаст.) 150/90
Safety.BpCardio порог «только кардио» по АД 140/90
Safety.RestingHrSitting порог пульса сидя для переноса тренировки 90
Safety.HrStrengthMax порог пульса в силовой части (предупреждение) 120
Safety.LightWeekHrRise рост пульса покоя (2 дня) для лёгкой недели +8

Сервер (appsettings.json):

Параметр Семантика Умолчание
Api.Key статический API-ключ по умолчанию (владелец) — (обязательный)
Api.Athletes список атлетов: { name, apiKey } — ключ идентифицирует атлета (изменение vision 1.1; управление — через веб-консоль, Ф-9.1) — (минимум владелец)
Admin.Login / Admin.PasswordHash учётные данные владельца для входа в веб-консоль (пароль — только хэш, изменение vision 1.2) — (обязательные)
Api.Port порт HTTPS 8443
Db.ConnectionString подключение к PostgreSQL — (обязательный)
Garmin.Login / Garmin.Password учётная запись Garmin Connect (решение — опросник 4.3) — (обязателен для fetch)
Garmin.DownloadDir папка хранения скачанных .fit data\fit
Import.Dir папка импорта fallback (ручной экспорт, опросник 4.3) data\import
Import.ArchiveDir папка обработанных файлов импорта data\import_done
Progression.BaseStepKg шаг прогрессии веса, кг 2.5
Progression.IsoStepKg шаг прогрессии изоляции, кг (умолчание 1,0; валидация 0,25–5 — коридор метрик «+0,5–1 кг»; решение владельца О-3-А) 1.0
Progression.BackoffPercent снижение при недовыполнении, % 5
Deload.MaxWeeks недель между делоадами 6
Safety.BpCancel порог отмены тренировки по АД (сист./диаст.) 150/90
Safety.BpCardio порог «только кардио» по АД 140/90
Safety.RestingHrSitting порог пульса сидя для переноса тренировки 90
Safety.HrStrengthMax порог пульса в силовой части (для red_flags) 120
Safety.LightWeekHrRise рост пульса покоя (2 дня) для лёгкой недели +8
Log.Path / Log.Level логи logs\, Info

🛡 Пароль Garmin и API-ключ — только в настройках, не в коде; логи их не содержат (З-2, З-6).

4. Функциональные требования

Ф-1. Голосовой учёт подходов (телефон)

  1. Активация — кнопкой микрофона на экране активной тренировки (решение — опросник 4.5); повторное нажатие выключает прослушивание. Пока экран активной тренировки открыт, распознавание работает офлайн, без сети.
  2. Грамматика команд (голос → семантика):
    • «Подход W на R» → подход: вес W кг × R повторений (вес — целые кг либо «…с половиной» → +0,5 кг, шаг 0,5; W — 0–500, R — 1–100; решение владельца О-2-Б);
    • «Вес W» → рабочий вес W кг для следующих подходов;
    • «Отдых S (секунд)» → таймер отдыха S секунд (5–600);
    • «РПЭ N» → RPE последнего подхода, N 1–10 (Ф-13.3, З-8).
  3. Команда вне грамматики или с числом вне диапазона — отклоняется: короткий сигнал ошибки, состояние не меняется, в лог пишется распознанный текст.
  4. Принятая команда: сохраняется в текущую тренировку, проигрывается короткий «щелчок» и голосовое подтверждение («Принято, подход 120 на 8» — TTS, офлайн).
  5. 🛡 Каждая команда фиксируется в журнале команд: исходный распознанный текст, семантика, время (секунды от начала тренировки) — журнал нужен для сопоставления с .fit (Ф-7.6) и не редактируется.
  6. Правка записанного подхода — не более 2 касаний (тап по подходу → правка веса/повторов), КУ-1.

Ф-2. Поле данных на часах (Monkey C)

  1. Метрики на экране: текущий пульс (шрифт 40–48 pt), средний пульс текущего подхода (от начала подхода до текущего момента), время с последнего Lap (границы подхода — Ф-2.3; включает предшествующий отдых — точное время «под нагрузкой» не измеряется: детекция повторений недоступна Connect IQ API, errata 2026-10-19).
  2. Зона пульса — цвет ободка/фона: синий < 50 %, зелёный 50–70 %, жёлтый 70–85 %, красный > 85 % от Hr.MaxBpm; границы — из настроек поля данных (Connect IQ settings; автоматическая передача с телефона — открытый вопрос 3).
  3. Границы подхода — между нажатиями кнопки Lap (штатная семантика «Силовой»: Lap — конец подхода, метки Lap попадают в .fit, КУ-2): событие Strength Set в Connect IQ API отсутствует (errata 2026-10-19 — класса повторений нет ни в одной версии платформы, проверено по актуальному API); метрики подхода считаются за интервал Lap→Lap и обнуляются на Lap.
  4. Вибрация: однократная лёгкая — конец автономного таймера отдыха поля (длительность — настройка поля в Garmin Connect Mobile, умолчание Rest.DefaultSec); двойная — выход пульса за красную зону. Передача длительности с телефона — v2 (errata ОВ-3 от 2026-10-19: канал часов односторонний, часы → телефон); часы не блокируются (не зависимость от телефона).
  5. Кнопка Lap — штатная: фиксирует конец подхода/круга в записи активности (требование — метки Lap попадают в .fit, КУ-2).
  6. Кнопка Start/Stop — штатная пауза/стоп активности; поле не требует подтверждений и не блокирует штатное сохранение тренировки.
  7. 🛡 Поле не пишет в сеть и не хранит историю: только отображение; запись ведёт сама платформа Garmin.
  8. Разметка экрана — на ресурсы макета по семействам разрешений; функциональное поведение (Ф-2.1–Ф-2.7) одинаково на всех целевых моделях; функциональность, отсутствующая на модели (например, вибрация), молча пропускается — поле не падает (изменение vision 1.1).

Ф-3. Экран активной тренировки (телефон)

  1. Статусная строка: связь с часами (зелёный/красный/серый — серый = связь недоступна, приложение не блокируется), заряд часов (если передаётся), статус сети (онлайн/офлайн).
  2. Пульс: крупное текущее значение + линия за последний подход; источник — штатная трансляция пульса часов «Broadcast Heart Rate», приём по BLE Heart Rate Service (errata ОВ-3 от 2026-10-19: companion-канал Connect IQ на fenix 6X недоступен для полей данных, CIQ ≤ 4.1.7; транспорт платформо-независимый — любые часы со стандартной трансляцией). Если связи нет — прочерк; запись голосом работает (Ф-1.1).
  3. Таймер отдыха: обратный отсчёт, фон — красный (идёт отдых), жёлтый (последние 10 с), зелёный (время начинать); старт — командой «Отдых S» или кнопкой (умолчание Rest.DefaultSec).
  4. Блок упражнения: текущее упражнение (из активной программы, Ф-11.2) и текущий рабочий вес.
  5. Кнопки нижней панели: микрофон (Ф-1.1), «Сбросить» (отмена текущей тренировки с подтверждением — тренировка помечается cancelled и сохраняется в историю).
  6. На экране одновременно ≤ 4 активных элемента, тёмная тема, крупные зоны касания (vision 2.2); UI/UX-стандарт (3-tech\ui-ux-recommendations.md): шрифт ≥ 16 pt, контраст WCAG AA, цели касания ≥ 44 pt, действия одной руки — в нижней трети экрана; числовой ввод — пикеры с шагом 2,5 кг (не клавиатура), значение по умолчанию — последний использованный вес; цветовые сигналы дублируются текстом/иконкой (не только цветом).

Ф-4. Библиотека упражнений (телефон, синхронизируется на сервер)

  1. Сущность «Упражнение»: название (уникальное), двигательная группа (жим/тяга/ноги/… — из фиксированного справочника, нужна для правил замены и тоннажа), признак «базовое/изоляция».
  2. Операции: добавить, переименовать, удалить. 🛡 Удаление упражнения, на которое ссылаются программа или тренировки, — только логическое (is_active=0): история остаётся читаемой.
  3. 🛡 Идентификаторы упражнений (exercise_id) неизменяемы: программы и факты ссылаются по ID (дизайн LLM-планирования, разд. 2).
  4. 🛡 Библиотека принадлежит атлету (изоляция, изменение vision 1.1): упражнения другого атлета недоступны; общий справочник на всех — кандидат v2 (открытый вопрос 11).

Ф-5. История тренировок (телефон)

  1. Список завершённых тренировок: дата/время, длительность, средний пульс, число подходов, названия упражнений.
  2. Карточка тренировки: список подходов (упражнение, вес × повторения), пометки источника («голос», «часы», «правка»), средний пульс по подходам.
  3. Офлайн список строится из локальной БД (без сети).

Ф-6. Профиль и зоны пульса (телефон)

  1. Поля профиля: пол, возраст, вес (ввод однократно, редактируется); хранение — локально, синхронизируется на сервер (athlete_state).
  2. Зоны: 50/70/85 % от Hr.MaxBpm (п. 3); расчёт по умолчанию — формула максимальной ЧСС (открытый вопрос 1).
  3. Зоны используются телефоном (график, статусы) и передаются на часы в объёме, доступном каналу (открытый вопрос 3).

Ф-7. Офлайн-учёт и синхронизация (телефон ↔ сервер)

  1. 🛡 Все данные сначала пишутся в локальную БД телефона; сеть не стоит на пути записи (аналог КУ-3).
  2. Очередь sync_pending: каждая новая/изменённая сущность получает client_guid (UUID v4, генерирует телефон) и попадает в очередь; порядок — по времени создания; отправка — пакетами ≤ 50 записей. 🛡 Атлета определяет API-ключ: все записи пакета пишутся на сервере от его имени; телефон не передаёт идентификатор атлета в данных. 🛡 Каждая клиентская сущность идентифицируется UUID — первичным ключом и на телефоне, и на сервере (Р2-Б); UUID генерирует телефон (строки «только .fit» — сервер); ссылки дочерних записей — по тем же UUID, отдельный маппинг серверных id не нужен.
  3. Отправка: POST /api/v1/sync (пакет записей + client_guid каждой); успех записи на сервере подтверждается ответом (принятые GUID); подтверждённые удаляются из очереди. Неудача сети — тихий баннер «Синхронизация временно недоступна», повтор по восстановлению сети (и по Sync.WifiOnly).
  4. 🛡 Идемпотентность: сервер считает запись по client_guid — повтор пакета не создаёт дублей (КУ-3); ответ идемпотентен.
  5. После первой успешной синхронизации — тихий баннер «Данные успешно синхронизированы».
  6. Восстановление связи с часами: телефон запрашивает пропущенный период пульса (в объёме возможностей канала — открытый вопрос 3) и сопоставляет его с локально записанными подходами по времени (границы подхода из журнала команд Ф-1.5); пульс, не попавший в окно подхода, к подходам не относится.
  7. Конфликтов правок нет: один пользователь, единственный источник правки — телефон; сервер не меняет факт-записи (🛡).

Ф-8. Сервер: забор и парсинг .fit, REST API

  1. --mode fetch / расписание: неофициальный клиент Garmin Connect под учётной записью владельца (решение — опросник 4.3) скачивает .fit новых силовых тренировок в Garmin.DownloadDir (список уже скачанных — по fit_file_id в БД; повторный запуск не качает дубли — 🛡).
  2. Парсинг .fit (Garmin FIT SDK): извлекаются Session (тип strength_training, время), Lap (границы кругов/подходов), Record (дискретный пульс), Set (повторения/вес, если есть); результат — канонический JSON тренировки в workout_facts (дизайн LLM-планирования, разд. 4).
  3. Импорт (--mode import): файлы из Import.Dir — .fit, .tcx, .gpx (по документу форматов) и пакет программы program-import.json (формат — 3-tech\program-import-format.md, закрытый вопрос 12): пакет маппится на src.program/ src.program_version.body по external_id; повторный импорт пакета с тем же external_id — новая версия program_version. Файлы и пакеты парсятся тем же конвейером; обработанные перемещаются в Import.ArchiveDir; необработанные остаются с записью в логе (код возврата 2). Секция profile пакета в v1 не переносится (Safety-порогами управляет только конфиг Safety.*).
  4. Сопоставление факт ↔ голосовой учёт: тренировка .fit сопоставляется с тренировкой телефона по времени начала (± 15 минут) — сопоставлённая пара связывается; несопоставленные остаются раздельными (сопоставление не удаляет и не переписывает данные — 🛡).
  5. REST API (HTTPS, заголовок X-Api-Key = ключ атлета; без ключа или с чужим ключом — 401): POST /api/v1/sync (Ф-7.3); GET /api/v1/workouts (список с пагинацией); GET /api/v1/workouts/{id} (карточка); GET /api/v1/programs/active (активная версия программы). 🛡 Каждой запрос видит данные только своего атлета (изоляция, изменение vision 1.1).
  6. 🛡 API пишет факт-данные только из sync и импорта; ручного ввода на сервере нет.

Ф-9. Веб-интерфейс сервера — административная консоль владельца

🛡 Доступ в веб — только для владельца, вход по логину и паролю (Admin.Login / Admin.PasswordHash из настроек; открытый вопрос 6 закрыт); атлеты работают только через телефон (изменение vision 1.2). Разделы консоли:

  1. Атлеты (управление, открытый вопрос 9 закрыт этим решением): список, добавление атлета (имя + генерация API-ключа), смена ключа, блокировка (заблокированный ключ → 401 на API).
  2. Тренировки: таблица по всем атлетам с фильтром по атлету и дате (дата, длительность, средний пульс, подходы, упражнений), сортировка, пагинация; карточка тренировки: подходы, отчёт план/факт (Ф-11.4); ход тренировки — таймлайн из .fit (границы подходов по Lap, дискретный пульс по Record): начало/конец и длительность каждого подхода, средний и пиковый пульс подхода, отдых после подхода, пульсограмма за всю тренировку; выгрузка CSV текущей выборки (КУ-4).
  3. Программы: выбор атлета → список версий (статусы, автор, даты); создание и правка версий draft; смена активной версии (Ф-10.3); просмотр предложений правил (Ф-12.3) — применение предложения из консоли помечает версию author=admin.
  4. Метрики и динамика: по атлету и периоду — adherence, тоннаж по группам, динамика 1ПМ и рабочего веса по упражнениям (графики по неделям из workout_metrics); у каждой тренировки карточки — место в тренде (лучше/хуже предыдущей).
  5. Планы тренировок (план ↔ факт): расписание активной версии программы атлета по неделям и дням; по каждой запланированной тренировке — планируемые результаты (упражнения, подходы, вес × повторения, целевой объём) против фактических (выполнена/пропущена, подходы, веса, тоннаж, adherence); сводка выполнения плана за неделю и мезоцикл (доля запланированных/выполненных/пропущенных).

Ф-10. Программы тренировок (сервер + телефон)

  1. Программа — версионированный JSON-документ (схема — дизайн LLM-планирования, разд. 2): недели → тренировки (день, фокус) → упражнения (exercise_id из библиотеки) → подходы-план (вес, повторения, target_rpe, отдых). Хранение — таблица programs (PostgreSQL); каждая версия неизменяема (🛡). 🛡 Программы принадлежат атлету — у каждого свои (изменение vision 1.1).
  2. В v1 создание/правка версии — на телефоне (редактор программы атлета, author=user) или в административной консоли (владелец, author=admin, изменение vision 1.2); отправка на сервер — при синхронизации телефона либо сразу из консоли.
  3. Ровно одна версия в статусе active (🛡); смена активной — явным действием пользователя; выполненные тренировки ссылаются на версию, которая была активна на их начало (история не «поплывёт»).
  4. Статусы версии: draft → active → archived; переходы — действиями пользователя.

Ф-11. Контроль исполнения программы (план/факт)

  1. На экране активной тренировки — текущая позиция активной программы: упражнение, план подходов (вес × повторения), отметка выполненных.
  2. Подход фиксируется голосом (Ф-1) и помечается: «по плану» (вес и повторения = план ± допустимое отклонение: вес ± 2,5 кг, повторения ± 0) или «отклонение» (всё остальное).
  3. По завершении тренировки — отчёт план/факт: по каждому упражнению план (подходы × вес × повторения) против факта, доля закрытых подходов (adherence) (КУ-5).
  4. Отчёт доступен на телефоне и в веб-интерфейсе (Ф-9.2).

Ф-12. Правила прогрессии (без LLM, v1)

  1. После каждой синхронизированной тренировки MetricsEngine (сервер) считает по данным этого атлета: adherence (доля закрытых подходов), тоннаж по упражнению и группе, оценочный 1ПМ (формула — открытый вопрос 7) — в workout_metrics (дизайн LLM-планирования, разд. 4). 🛡 Метрики и правила считаются по каждому атлету независимо (изоляция, изменение vision 1.1).

  2. Микроправка весов на следующее занятие (правила, детерминированно):

    • все запланированные подходы закрыты «по плану» при RPE ≤ 7 (2 тренировки подряд) → вес + Progression.BaseStepKg (базовые),
      • Progression.IsoStepKg (изоляция, З-27/О-3-А);
    • RPE ≥ 9 в 2+ сетах → вес − Progression.BackoffPercent %;
    • повторения достигли верхней границы диапазона (15–20) → вес ↑, повторения к 12;
    • ≥ 2 подходов не дотянуты по повторениям → вес − Progression.BackoffPercent %;
    • иначе (частичное выполнение) — вес без изменения. Источник порогов — документ метрик («Метрики_тренировок_и_ самоконтроля.md», правила 3–5, МакРоберт).
  3. Правила применяются только к active версии; результат — предложение следующей версии программы со статусом draft (author=rules), показывается атлету в приложении диффом; применение — подтверждением атлета на телефоне или владельцем в консоли (Ф-9.3, изменение vision 1.2). 🛡 Автоматической смены активной версии нет (vision 2.4).

  4. Делоад: если Deload.MaxWeeks недель подряд без делоада, правило предлагает делоад-версию (объём −40–50 %) — тем же механизмом диффа (дизайн LLM-планирования, разд. 6).

  5. Красные флаги и лёгкая неделя (документ метрик, правила 1, 6, v1); источник данных — daily_log (тренд пульса покоя и самочувствия за 2 дня, Р1-А):

    • пульс покоя ≥ обычного +8 уд/мин два дня подряд или самочувствие ≤ 2 → следующая тренировка помечается лёгкой (60–70 % весов, 2 сета); 3+ дня — предложение отмены и совет к врачу;
    • боль в колене ≥ 1 два занятия подряд → предложение замены упражнения из той же группы (пара-замена из атрибутов упражнения).
  6. Офлайн-режим сервера: правила выполняются при следующем запуске serve/import — телефон при этом полнофункционален (учёт и локальные планы работают без сервера).

Ф-13. Самоконтроль и допуск к тренировке (телефон; изменение 1)

Источник порогов — документ метрик (..\..\Метрики_тренировок_и_самоконтроля.md, Жижин гл. 2–3, 6; Аттия гл. 10, 13; МакРоберт; CDC). Состав v1 — MVP-приоритет документа (его п. 5).

  1. Дневник-минимум (день, дом, 2–3 минуты): АД (сист./диаст.), вес тела, пульс покоя (утро, до подъёма — Р1-А), самочувствие 1–5; экран «Сегодня» с вводом за 2–3 касания. Данные — в LocalDb и на сервер (daily_log); пульс покоя и самочувствие — данные правила 1 (Ф-12.5, КУ-7).
  2. Предстартовый допуск: перед стартом силовой тренировки — экран допуска: пульс сидя (с часов, если связаны, иначе ввод вручную) и АД за сегодня. Пороги:
    • АД > 150/90 → тренировка не начинается: предложение прогулки, кнопка «Отменить» (🛡);
    • АД 140–150/90–95 → только лёгкое кардио/дыхание (силовые заблокированы);
    • пульс сидя > 90 уд/мин → предложение перенести тренировку (старт — явным подтверждением «всё равно начать»).
  3. По сетам: RPE (цель 6–8) — голосом «РПЭ N» для последнего подхода или тапом 1–10; боль в колене 0–10 — тапом, только для упражнений группы «ноги»; сохраняется с подходом (workout_set).
  4. После тренировки: время возврата пульса к < 90 уд/мин — считается автоматически из .fit (Record после последнего Lap); показывается в карточке и попадает в метрики.
  5. 🛡 Пороги допуска — конфигурируемые в настройках телефона (Safety.*, умолчания — документ метрик; Р3-А); серверные Safety.* применяются серверными правилами (red_flags); обход блокировки «Отменить» логируется.
  6. Талия и сон (утренняя телеметрия) и правила координации 7–10 — v2; контрольные тесты — v3 (документ метрик, п. 5).
  7. Во время силовой части: пульс > Safety.HrStrengthMax (умолчание 120) → предупреждение на телефоне (баннер + вибро, спокойная формулировка по UI/UX-стандарту); на часы порог передаётся в объёме канала (ОВ-3). Источник — документ метрик (п. 2.3); значение перенесено в параметр конфигурации Safety.HrStrengthMax (разд. 3, умолчание 120). Программа тренировок — импортируемые данные атлета (см. открытый вопрос 12); нормативным источником требований не является (З-30, уточнение владельца 2026-10-17).

Ф-14. Перерывы и возврат в режим (телефон + сервер; изменение 2)

Источник — документ Перерывы_подводные_камни_и_рекомендации.md (МакРоберт, CDC «Staying on Track», Жижин гл. 5–6, Аттия). Модель: active → break → return → active.

  1. 🛡 Break вычисляется автоматически: пропущены все запланированные сессии за 4 дня подряд → программа переводится в статус break (Жижин гл. 6: эффект тает с 4-го дня). Break ставится автоматически по пропускам (основной путь); атлет может объявить перерыв заранее (Ф-14.2, «уезжаю в отпуск») — такой break создаётся с source=manual; произвольного ручного включения без объявления нет.

  2. Причина запрашивается у атлета: при срабатывании автомат показывает вопрос «Вы пропустили тренировки — что случилось?» с выбором типа (болезнь / отпуск / аврал-недосып / травма / другое) и предполагаемой даты возврата; до ответа тип — «не указана» (правила 12–14 применяются после ответа). При типе «болезнь с температурой» — минимум 3 дня после нормальной температуры до первой сессии (правило 12). Атлет может объявить break заранее («уезжаю в отпуск») — запланированный простой попадает в тот же автомат. Примечание (З-39, решение владельца 2026-10-18): признака «с температурой» в данных breaks нет — в v1 любой break kind=illness трактуется правилом возврата как перезапуск (коэффициент нижней границы, spec 04 m05); различение «с температурой» — кандидат v2.

  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), пакеты синхронизации (число записей, результат), забор/парсинг .fit (файл, результат), применённые версии программ.
  2. Error: все ошибки с текстом исключения (этап, объект, причина).
  3. 🛡 В логах нет пароля Garmin, API-ключей и содержимого речи (только распознанный текст команды — он нужен для диагностики распознавания).

5. Контракты и инварианты

  • 🛡 Независимость частей: часы, телефон и сервер работают при отсутствии остальных; ни одна часть не блокирует другую (БЦ-4).
  • 🛡 Офлайн-first: запись (голос, часы) и просмотр истории никогда не ждут сеть; сеть — только синхронизация (КУ-3).
  • 🛡 Идемпотентность: повтор отправки пакета (по client_guid) и повторный fetch/import не создают дублей (КУ-3, Ф-8.1).
  • 🛡 Неизменяемость истории: версии программ неизменяемы; факт-записи сервер не переписывает; удаление упражнения — только логическое.
  • 🛡 Изоляция атлетов: API-ключ идентифицирует атлета; ни API, ни веб не отдают атлету чужие данные; метрики, правила и программы считаются по атлетам независимо (изменение vision 1.1).
  • 🛡 Тайны: пароль Garmin, API-ключи и хэш пароля владельца — только в настройках/БД; в логах их нет.
  • 🛡 Безопасность нагрузки: автоматические изменения программы ограничены лимитами правил (Ф-12.2, Ф-12.4); смена активной версии — только вручную (БР-5, vision 2.4).
  • Отмена тренировки: «Сбросить» сохраняет тренировку как cancelled — молчаливой потери данных нет.

6. Трассировка

Функция Бизнес-цель Критерий успеха Версия
Ф-1 голосовой учёт БЦ-1 КУ-1 v1
Ф-2 поле данных на часах БЦ-2 КУ-2 v1
Ф-3 экран тренировки БЦ-1, БЦ-2 КУ-1 v1
Ф-4 библиотека БЦ-3 — v1
Ф-5 история (телефон) БЦ-3 — v1
Ф-6 профиль и зоны БЦ-2 КУ-2 v1
Ф-7 офлайн + синхронизация БЦ-4 КУ-3 v1
Ф-8 сервер (.fit, API) БЦ-5 КУ-2, КУ-4 v1
Ф-9 веб + CSV БЦ-5 КУ-4 v1
Ф-10 программы БЦ-3 КУ-5 v1
Ф-11 план/факт БЦ-3 КУ-5 v1
Ф-12 правила прогрессии БЦ-3 КУ-6 v1
Ф-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
Бег/вело — — v3+

7. Открытые вопросы

# Вопрос Контекст Решение
1 Формула максимальной ЧСС Умолчание для зон (Ф-6.2): 220 − возраст (классика) или Танака (208 − 0,7×возраст, точнее для пожилых); можно — ручной ввод Hr.MaxBpm Закрыт шагом 5
2 Офлайн-движок распознавания Vosk (модель ~50 МБ, ru) против sherpa-onnx; грамматика цифр шумного зала; влияет на точность КУ-1. Кандидаты проверяются прототипом Закрыт шагом 5
3 Канал телефон ↔ часы Connect IQ companion (Communications): что передаётся реально (пульс live, зоны, таймер отдыха, заряд); ограничения канала определяют Ф-2.4, Ф-3.2, Ф-6.3. Прототип на шаге 4 Закрыт шагом 4; errata 2026-10-19: companion-канал на fenix 6X нереализуем (CIQ ≤ 4.1.7) — транспорт = штатная BLE-трансляция пульса, канал односторонний (Ф-3.2)
4 Расписание fetch cron/systemd-таймер на сервере против внутреннего планировщика; предпочтителен внешний планировщик Закрыт шагом 5
5 Способ сопоставления тренировок телефон ↔ .fit Окно ± 15 минут (Ф-8.4) против точной метки начала из sync ✅ Закрыт в этом документе (раздел 4, Ф-8.4)
6 Доступ в веб-интерфейс ✅ Закрыт изменением vision 1.2: веб — административная консоль владельца, вход по логину и паролю (раздел 4, Ф-9); атлеты — только телефон ✅ Закрыт (изменение vision 1.2)
7 Формула оценочного 1ПМ Эпли против Бжицки (разд. 4 дизайна LLM-планирования); различие ~5 % на малых повторениях Закрыт шагом 5
8 Перечень моделей часов v1 Якорь — Fenix 6X, 280×280 (изменение vision 1.1; уточнение владельца 2026-10-17 — vision 1.5); каждая модель — конфигурация сборки (экран, память). Кандидаты: модели с профилем «Силовая» и Connect IQ 4+ у участников; список фиксируется по фактическому парку устройств Закрыт шагом 4
9 Способ заведения атлетов ✅ Закрыт изменением vision 1.2: раздел «Атлеты» веб-консоли владельца (Ф-9.1) — имя + генерация ключа, смена ключа, блокировка; стартовые данные владельца — в конфиге ✅ Закрыт (изменение vision 1.2)
10 Источник .fit для атлетов без учётки владельца fetch идёт под учётной записью владельца (опросник 4.3); другие атлеты: (а) делят доступ к своему Garmin (передача файла в папку импорта), (б) свой экземпляр учётки в конфиге, (в) только ручной импорт. Кандидат для v1 — (в) папка импорта ✅ Закрыт (ревью №2, О-1-А): v1 — только папка импорта (--mode import); fetch — под единственной учёткой владельца; собственные учётки атлетов в конфиге — кандидат v2 (tech-requirements, ОВ-10). Уточнение владельца: атлет регистрируется на телефоне (имя), привязка — по uuid клиентского приложения
12 Импорт пакета программы (program-import.json) Пакет — механизм эксплуатации (уточнение владельца 2026-10-17); формат, маппинг на src.program/program_version.body, поведение при повторном импорте ✅ Закрыт (ревью №3, О-4-Б): импорт в v1 через --mode import; формат — 3-tech\program-import-format.md; external_id — идентификатор пакета; секция profile в v1 игнорируется
11 Общий справочник упражнений Сейчас библиотека у каждого атлета своя (Ф-4.4); общий справочник + личные дополнения — кандидат v2 (дубли при малом числе атлетов не критичны) Открыт (до v2)