address greptile review feedback (greploop iteration 3)

- Guard naive expires_at in CREATE path to prevent 500 TypeError
- Auto-recompute next_run_at when schedule fields change via PATCH
- Reject schedule_kind='once' with fire_once=False to prevent infinite loop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Krrish Dholakia 2026-05-01 12:39:02 -07:00
parent 621d74a478
commit 0cc6787286

View file

@ -128,11 +128,20 @@ async def create_scheduled_task(
)
now = datetime.now(timezone.utc)
if data.expires_at <= now:
expires_at = data.expires_at
if expires_at.tzinfo is None:
expires_at = expires_at.replace(tzinfo=timezone.utc)
if expires_at <= now:
raise HTTPException(status_code=400, detail="expires_at must be in the future")
fire_once = data.fire_once if data.fire_once is not None else (data.schedule_kind == "once")
if data.schedule_kind == "once" and not fire_once:
raise HTTPException(
status_code=400,
detail="fire_once=False is invalid with schedule_kind='once'",
)
next_run_at = compute_next_run(
kind=data.schedule_kind,
spec=data.schedule_spec,
@ -296,6 +305,24 @@ async def update_scheduled_task(
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
if (
any(k in fields for k in ("schedule_kind", "schedule_spec", "schedule_tz"))
and "next_run_at" not in fields
):
fields["next_run_at"] = compute_next_run(
kind=merged_kind,
spec=merged_spec,
tz=merged_tz,
from_time=datetime.now(timezone.utc),
)
merged_fire_once = fields.get("fire_once", existing.fire_once)
if merged_kind == "once" and not merged_fire_once:
raise HTTPException(
status_code=400,
detail="fire_once=False is invalid with schedule_kind='once'",
)
merged_action = fields.get("action", existing.action)
merged_check = fields.get("check_prompt", existing.check_prompt)
if merged_action == "check" and not merged_check: