feat: persist exact Week Ahead task times (Closes #1270)
CI / lint (pull_request) Successful in 4m3s
CI / build-release (pull_request) Successful in 8s
CI / browser-journey (pull_request) Successful in 6m22s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-22 16:39:24 +00:00
1 parent f78da3dfc9
commit 5fb4da30a4
11 files changed
+180 -18

No files matched your search

+1
View File
@@ -738,6 +738,7 @@ class WeekPlanDay(BaseModel):
capacity_minutes: int | None = Field(default=None, ge=15, le=1440)
estimates: dict[str, int] = Field(default_factory=dict, max_length=5)
free_windows: list[WeekFreeWindow] | None = Field(default=None, max_length=16)
start_times: dict[str, str] = Field(default_factory=dict, max_length=5)
class WeekPlanUpdate(BaseModel):
+33
View File
@@ -578,6 +578,39 @@ class TodayStore:
})
previous_end = end
plan["free_windows"] = normalized_windows
if "start_times" in day:
start_times = day["start_times"]
if not isinstance(start_times, dict) or len(start_times) > 5:
raise ValueError("task start times must be a bounded object")
if not set(start_times).issubset(plan["ids"]):
raise ValueError("task start times must belong to work on the same date")
occupied = []
for identity in plan["ids"]:
if identity not in start_times:
continue
value = start_times[identity]
if (
not isinstance(value, str) or len(value) != 5 or value[2] != ":"
or not value[:2].isdigit() or not value[3:].isdigit()
or int(value[:2]) > 23 or int(value[3:]) > 59
):
raise ValueError("task start times must use HH:mm times")
start = int(value[:2]) * 60 + int(value[3:])
minutes = plan["estimates"].get(identity)
if not isinstance(minutes, int) or start + minutes > 1440:
raise ValueError("task start times must fit their estimates within the date")
end = start + minutes
if any(start < other_end and end > other_start for other_start, other_end in occupied):
raise ValueError("task start times must not overlap")
windows = plan.get("free_windows")
if windows and not any(
int(window["start_time"][:2]) * 60 + int(window["start_time"][3:]) <= start
and end <= int(window["end_time"][:2]) * 60 + int(window["end_time"][3:])
for window in windows
):
raise ValueError("task start times must fit retained free windows")
occupied.append((start, end))
plan["start_times"] = {identity: start_times[identity] for identity in plan["ids"] if identity in start_times}
duplicate_ids = seen_ids.intersection(plan["ids"])
if duplicate_ids:
raise ValueError("work must be assigned to only one Week Ahead date")