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

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

  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)