# Спецификация 05: обвязка sync и DI Источники: Ф-12.1 («после каждой синхронизированной тренировки»), Ф-14.6 (офлайн-режим: правила — при следующем sync), образец — m04 spec 04. ## 1. Порядок в SyncService (после пересчёта метрик m04) Для каждого workout из пакета, после `ComputeForWorkout`: ```csharp try { breakEngine.CloseOnReturn(athleteId, workout, today); } catch (Exception ex) { logger.LogWarning(ex, "rules: возврат не удался ({WorkoutId})", id); } try { progressionRules.EvaluateAfterWorkout(athleteId, workoutId); } catch (Exception ex) { logger.LogWarning(ex, "rules: микроправка не удалась ({WorkoutId})", id); } ``` Один раз на пакет (не на workout): ```csharp try { breakEngine.DetectBreak(athleteId, today); } catch (Exception ex) { logger.LogWarning(ex, "rules: детект break не удался"); } try { progressionRules.CheckDeload(athleteId, today); } catch (Exception ex) { logger.LogWarning(ex, "rules: делоад не удался"); } ``` - 🛡 сбой правил не влияет на ответ sync (200, как у метрик); - всё после `scope.Complete()` (errata m04 №3 — TransactionScope); - логирование — `ILogger` (errata m04 №4). ## 2. DI (WebAppStartup) ``` AddSingleton(config.Progression); // ProgressionConfig AddSingleton(); AddSingleton(); ``` Конструкторы (по факту, З-42 п. 3; все зависимости уже зарегистрированы m01–m04): ```csharp ProgressionRules(IWorkoutRepository, IExerciseRepository, ProgramStore, ProgressionConfig) BreakEngine(IWorkoutRepository, IBreakRepository, ProgramStore, ProgressionConfig) ``` (Ранняя редакция с `IWorkoutMetricsRepository` не реализована: опорная точка делаода читается через репозиторий тренировок — `session_kind=deload`, иначе `CreatedAt` активной версии, см. spec 03.) ## 3. Конфиг (ServerConfig) `ServerConfig.Progression` (`ProgressionConfig`), `Load` из секции `progression`, `Validate` → ошибки старта. Секция добавляется в `appsettings.json` и `appsettings.test.json`. ## 4. Инварианты 🛡 - правила вызываются только после коммита пакета и метрик; - сбой любого шага — Warning, sync успешен (module_reqs 🛡5); - правила ничего не пишут кроме `program_version` (draft через ProgramStore) и `breaks` (🛡4).