# Decision Engine Specification ## Job to Be Done When I check the app, I want a clear training decision based on my current biometrics and cycle phase, so that I avoid overtraining while managing Hashimoto's. ## Decision Status Hierarchy Decisions are evaluated in priority order. First matching rule wins. ### Priority 1: HRV Unbalanced → REST ``` IF hrvStatus == "Unbalanced" THEN REST Reason: "HRV Unbalanced" ``` HRV imbalance indicates autonomic stress. No training. ### Priority 2: Body Battery Depleted → REST ``` IF bbYesterdayLow < 30 THEN REST Reason: "BB too depleted" ``` Yesterday's low BB < 30 indicates insufficient recovery. ### Priority 3: Late Luteal Phase → GENTLE ``` IF phase == "LATE_LUTEAL" THEN GENTLE Reason: "Gentle rebounding only (10-15min)" ``` PMS window - only gentle movement allowed. ### Priority 4: Menstrual Phase → GENTLE ``` IF phase == "MENSTRUAL" THEN GENTLE Reason: "Gentle rebounding only (10min)" ``` Menstruation - even gentler than late luteal. ### Priority 5: Weekly Limit Reached → REST ``` IF weekIntensity >= phaseLimit THEN REST Reason: "WEEKLY LIMIT REACHED - Rest" ``` Prevents overtraining within phase constraints. ### Priority 6: Current BB Low → LIGHT ``` IF bbCurrent < 75 THEN LIGHT Reason: "Light activity only - BB not recovered" ``` Current energy insufficient for full training. ### Priority 7: Current BB Medium → REDUCED ``` IF bbCurrent < 85 THEN REDUCED Reason: "Reduce intensity 25%" ``` Slight energy deficit - reduce but don't skip. ### Priority 8: Default → TRAIN ``` ELSE TRAIN Reason: "OK to train - follow phase plan" ``` All systems go - follow normal phase programming. ## Decision Statuses | Status | Icon | Meaning | |--------|------|---------| | REST | 🛑 | No training today | | GENTLE | 🟡 | Light rebounding only (10-15 min) | | LIGHT | 🟡 | Light activity, no intensity | | REDUCED | 🟡 | Normal activity, reduce intensity 25% | | TRAIN | ✅ | Full training per phase plan | ## Override Integration Active overrides in `user.activeOverrides[]` bypass algorithmic decision: | Override | Forced Decision | |----------|-----------------| | `flare` | REST | | `stress` | REST | | `sleep` | GENTLE | | `pms` | GENTLE | Override priority: flare > stress > sleep > pms ## Input Data Structure ```typescript interface DailyData { hrvStatus: HrvStatus; // "Balanced" | "Unbalanced" | "Unknown" bbYesterdayLow: number; // 0-100 phase: CyclePhase; // Current menstrual phase weekIntensity: number; // Minutes this week phaseLimit: number; // Max minutes for phase bbCurrent: number; // 0-100 } ``` ## Output Decision Structure ```typescript interface Decision { status: DecisionStatus; // REST | GENTLE | LIGHT | REDUCED | TRAIN reason: string; // Human-readable explanation icon: string; // Emoji indicator } ``` ## Decision Engine (`src/lib/decision-engine.ts`) **Function:** - `getTrainingDecision(data: DailyData): Decision` ## Success Criteria 1. HRV Unbalanced always forces REST regardless of other metrics 2. Phase limits are respected (no training when limit reached) 3. Overrides take precedence when active 4. Decision reason clearly explains the limiting factor ## Acceptance Tests - [ ] HRV Unbalanced returns REST - [ ] BB yesterday low < 30 returns REST - [ ] Late luteal phase returns GENTLE - [ ] Menstrual phase returns GENTLE - [ ] Week intensity >= limit returns REST - [ ] BB current < 75 returns LIGHT - [ ] BB current 75-84 returns REDUCED - [ ] BB current >= 85 with good metrics returns TRAIN - [ ] Priority order is maintained (HRV beats BB beats phase)