From 02394ea19c9c3dd6c6a7eadc81312725bb69fd7b Mon Sep 17 00:00:00 2001 From: Lars Date: Sat, 28 Mar 2026 08:50:55 +0100 Subject: [PATCH] fix: Phase 0b - fix remaining calculation bugs from log analysis Bugs fixed based on actual error logs: 1. TypeError: progress_pct None handling - changed .get('progress_pct', 0) to (goal.get('progress_pct') or 0) 2. UUID Error: focus_area_id query - changed WHERE focus_area_id = %s to WHERE key = %s 3. NameError: calculate_recovery_score_v2 - added missing import in calculate_category_progress 4. UndefinedColumn: c_thigh_r - removed left/right separation, only c_thigh exists 5. UndefinedColumn: resting_heart_rate - fixed remaining AVG(resting_heart_rate) to AVG(resting_hr) 6. KeyError: total_sleep_min - changed dict access to duration_minutes Changes: - scores.py: Fixed progress_pct None handling, focus_area key query, added recovery import - body_metrics.py: Fixed thigh_28d_delta to use single c_thigh column - recovery_metrics.py: Fixed resting_hr SELECT queries, fixed sleep_debt dict access All errors from logs should now be resolved. Co-Authored-By: Claude Opus 4.6 --- backend/calculations/body_metrics.py | 9 ++++----- backend/calculations/recovery_metrics.py | 6 +++--- backend/calculations/scores.py | 5 +++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/calculations/body_metrics.py b/backend/calculations/body_metrics.py index 5bb6d39..1558d1d 100644 --- a/backend/calculations/body_metrics.py +++ b/backend/calculations/body_metrics.py @@ -224,14 +224,13 @@ def calculate_arm_28d_delta(profile_id: str) -> Optional[float]: def calculate_thigh_28d_delta(profile_id: str) -> Optional[float]: - """Calculate 28-day thigh circumference change (cm, average of L/R)""" - left = _calculate_circumference_delta(profile_id, 'c_thigh', 28) - right = _calculate_circumference_delta(profile_id, 'c_thigh_r', 28) + """Calculate 28-day thigh circumference change (cm)""" + delta = _calculate_circumference_delta(profile_id, 'c_thigh', 28) - if left is None or right is None: + if delta is None: return None - return round((left + right) / 2, 1) + return round(delta, 1) def _calculate_circumference_delta(profile_id: str, column: str, days: int) -> Optional[float]: diff --git a/backend/calculations/recovery_metrics.py b/backend/calculations/recovery_metrics.py index 821c6bc..529a824 100644 --- a/backend/calculations/recovery_metrics.py +++ b/backend/calculations/recovery_metrics.py @@ -161,7 +161,7 @@ def _score_rhr_vs_baseline(profile_id: str) -> Optional[int]: # Get baseline (28d average, excluding last 3 days) cur.execute(""" - SELECT AVG(resting_heart_rate) as baseline_rhr + SELECT AVG(resting_hr) as baseline_rhr FROM vitals_baseline WHERE profile_id = %s AND resting_hr IS NOT NULL @@ -351,7 +351,7 @@ def calculate_rhr_vs_baseline_pct(profile_id: str) -> Optional[float]: # Baseline cur.execute(""" - SELECT AVG(resting_heart_rate) as baseline_rhr + SELECT AVG(resting_hr) as baseline_rhr FROM vitals_baseline WHERE profile_id = %s AND resting_hr IS NOT NULL @@ -407,7 +407,7 @@ def calculate_sleep_debt_hours(profile_id: str) -> Optional[float]: ORDER BY date DESC """, (profile_id,)) - sleep_data = [row['total_sleep_min'] for row in cur.fetchall()] + sleep_data = [row['duration_minutes'] for row in cur.fetchall()] if len(sleep_data) < 10: # Need at least 10 days return None diff --git a/backend/calculations/scores.py b/backend/calculations/scores.py index 3cf146f..f75e882 100644 --- a/backend/calculations/scores.py +++ b/backend/calculations/scores.py @@ -404,7 +404,7 @@ def get_top_priority_goal(profile_id: str) -> Optional[Dict]: for goal in goals: # Progress gap (0-100, higher = further from target) - goal['progress_gap'] = 100 - goal.get('progress_pct', 0) + goal['progress_gap'] = 100 - (goal.get('progress_pct') or 0) # Get focus areas for this goal with get_db() as conn: @@ -480,7 +480,7 @@ def calculate_focus_area_progress(profile_id: str, focus_area_id: str) -> Option JOIN goal_focus_contributions gfc ON g.id = gfc.goal_id WHERE g.profile_id = %s AND gfc.focus_area_id = ( - SELECT id FROM focus_area_definitions WHERE focus_area_id = %s + SELECT id FROM focus_area_definitions WHERE key = %s ) AND g.status = 'active' """, (profile_id, focus_area_id)) @@ -533,6 +533,7 @@ def calculate_category_progress(profile_id: str, category: str) -> Optional[int] from calculations.activity_metrics import calculate_activity_score return calculate_activity_score(profile_id) elif score_func_name == 'recovery_score': + from calculations.recovery_metrics import calculate_recovery_score_v2 return calculate_recovery_score_v2(profile_id) elif score_func_name == 'data_quality_score': return calculate_data_quality_score(profile_id)