Coverage for app / priorityScoring.py: 100%
32 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-26 21:50 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-03-26 21:50 +0000
1from datetime import datetime
2import math
5def clamp(x, lo, hi):
6 return max(lo, min(hi, x))
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
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
30 durationHours = max(task.length / 60, 0.01)
31 hoursUntilDue = (task.due_at - datetime.now()).total_seconds() / 3600.0
33 if task.completed:
34 return 0.0
36 # Emergency: must start now or very soon
37 if hoursUntilDue <= durationHours * emergencyBuffer:
38 return 100.0
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)
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)
50 # Shortness
51 shortnessScore = typicalDuration / (typicalDuration + durationHours)
52 shortnessScore = clamp(shortnessScore, 0.0, 1.0)
54 # Anti-starvation with stronger fade
55 pressure = clamp((userImportanceScore + urgencyScore) / 2.0, 0.0, 1.0)
56 effectiveShortnessWeight = weightShortness * (1.0 - antiStarvation * pressure)
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
64 # Base score
65 score = 100.0 * (wI * userImportanceScore + wU * urgencyScore + wS * shortnessScore)
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)
71 # Ensure that score is between 0 and 100, and rounded
72 return round(clamp(score, 0.0, 100.0))