3.6 KiB
3.6 KiB
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
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
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
- HRV Unbalanced always forces REST regardless of other metrics
- Phase limits are respected (no training when limit reached)
- Overrides take precedence when active
- 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)