Files
phaseflow/specs/decision-engine.md
2026-01-10 17:13:18 +00:00

144 lines
3.6 KiB
Markdown

# 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)