Coverage for app / priorityScoring.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-26 21:50 +0000

1from datetime import datetime 

2import math 

3 

4 

5def clamp(x, lo, hi): 

6 return max(lo, min(hi, x)) 

7 

8 

9def scoreTask(task, urgencyHorizon=6.0, typicalDuration=1.0, emergencyBuffer=1.1): 

10 """ 

11 Args: 

12 Task 

13 task.importance: User rating 1-10 

14 task.completed: Boolean, if the task is completed 

15 task.length: Estimated time to complete in minuites 

16 task.due_at: Datetime in which the task is due 

17 

18 Optional Args: 

19 urgencyHorizon: Hours at which urgency starts ramping 

20 typicalDuration: Reference point for "short" tasks 

21 emergencyBuffer: Multiplier for emergency threshold (default 1.1) 

22 if hoursUntilDue <= durationHours * emergencyBuffer, then we set priority to 100 

23 """ 

24 # Style parameters 

25 weightImportance = 0.65 

26 weightUrgency = 0.30 

27 weightShortness = 0.25 

28 antiStarvation = 0.7 

29 

30 durationHours = max(task.length / 60, 0.01) 

31 hoursUntilDue = (task.due_at - datetime.now()).total_seconds() / 3600.0 

32 

33 if task.completed: 

34 return 0.0 

35 

36 # Emergency: must start now or very soon 

37 if hoursUntilDue <= durationHours * emergencyBuffer: 

38 return 100.0 

39 

40 # Importance with diminishing returns at high end 

41 rawImportance = clamp((task.importance - 1.0) / 9.0, 0.0, 1.0) 

42 userImportanceScore = math.sqrt(rawImportance) 

43 

44 # Urgency 

45 # Slack hours is the number of hours we have remaining if we were to complete the task now 

46 remainingSlackHours = hoursUntilDue - durationHours 

47 urgencyScore = urgencyHorizon / (urgencyHorizon + remainingSlackHours) 

48 urgencyScore = clamp(urgencyScore, 0.0, 1.0) 

49 

50 # Shortness 

51 shortnessScore = typicalDuration / (typicalDuration + durationHours) 

52 shortnessScore = clamp(shortnessScore, 0.0, 1.0) 

53 

54 # Anti-starvation with stronger fade 

55 pressure = clamp((userImportanceScore + urgencyScore) / 2.0, 0.0, 1.0) 

56 effectiveShortnessWeight = weightShortness * (1.0 - antiStarvation * pressure) 

57 

58 # Normalize weights so they sum to the total 

59 total = weightImportance + weightUrgency + effectiveShortnessWeight 

60 wI = weightImportance / total 

61 wU = weightUrgency / total 

62 wS = effectiveShortnessWeight / total 

63 

64 # Base score 

65 score = 100.0 * (wI * userImportanceScore + wU * urgencyScore + wS * shortnessScore) 

66 

67 # Boost for high-importance AND high-urgency tasks 

68 if urgencyScore > 0.75 and userImportanceScore > 0.7: 

69 score = min(score * 1.15, 99.5) 

70 

71 # Ensure that score is between 0 and 100, and rounded 

72 return round(clamp(score, 0.0, 100.0))