Found while validating the scheduled-tasks feature in PR #344. Both are fixed in that PR; opening this issue for traceability.
Bug 1 — update() silently drops lastRunAt / lastRunStatus
ScheduledTasks.update(id, patch) only handles name, description, cron, workspaceId, prompt, and enabled. It ignores lastRunAt and lastRunStatus, so fire() / runNow() call update(task.id, { lastRunAt, lastRunStatus: "ok" }) but the run status is never persisted.
Impact: "Run now" and scheduled runs never record their last-run time/status, so the UI always shows the task as never-run.
Fix: apply lastRunAt / lastRunStatus in update() (see PR #344).
Bug 2 — nextRunAfter() stalls on never-matching cron
The next-run scan re-parses the cron expression on every minute iteration and scans up to 5 years. For a never-matching expression like 0 0 31 2 * (Feb 31) it loops ~2.6M times and takes ~1.9s, freezing the UI on every keystroke in the cron editor.
Impact: typing an impossible date combination into the cron field hangs the renderer.
Fix: parse once outside the loop and bound the scan to 4 years (covers the leap-year cycle), reducing worst case from ~1870ms to ~206ms (see PR #344).
Found while validating the scheduled-tasks feature in PR #344. Both are fixed in that PR; opening this issue for traceability.
Bug 1 —
update()silently dropslastRunAt/lastRunStatusScheduledTasks.update(id, patch)only handlesname,description,cron,workspaceId,prompt, andenabled. It ignoreslastRunAtandlastRunStatus, sofire()/runNow()callupdate(task.id, { lastRunAt, lastRunStatus: "ok" })but the run status is never persisted.Impact: "Run now" and scheduled runs never record their last-run time/status, so the UI always shows the task as never-run.
Fix: apply
lastRunAt/lastRunStatusinupdate()(see PR #344).Bug 2 —
nextRunAfter()stalls on never-matching cronThe next-run scan re-parses the cron expression on every minute iteration and scans up to 5 years. For a never-matching expression like
0 0 31 2 *(Feb 31) it loops ~2.6M times and takes ~1.9s, freezing the UI on every keystroke in the cron editor.Impact: typing an impossible date combination into the cron field hangs the renderer.
Fix: parse once outside the loop and bound the scan to 4 years (covers the leap-year cycle), reducing worst case from ~1870ms to ~206ms (see PR #344).