From b6156fdd796882640d3bae083d65ce3b58536e49 Mon Sep 17 00:00:00 2001 From: santhreal <64453045+santhreal@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:24:46 -0700 Subject: [PATCH] fix(cron): also coerce null createdAtMs/updatedAtMs on load Same present-null footgun as runHistory; route all required store ints through _store_int. --- nanobot/cron/types.py | 12 +++++------- tests/cron/test_cron_service.py | 6 ++++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/nanobot/cron/types.py b/nanobot/cron/types.py index 772aee40..563cd0c2 100644 --- a/nanobot/cron/types.py +++ b/nanobot/cron/types.py @@ -8,7 +8,7 @@ from typing import Any, Literal from nanobot.utils.dict_keys import get_camel_snake -def _required_store_int(value: Any, default: int = 0) -> int: +def _store_int(value: Any, default: int = 0) -> int: """Coerce JSON numerics to int; treat null/blank like a missing key.""" if value is None or value == "": return default @@ -85,11 +85,9 @@ class CronRunRecord: @classmethod def from_store_dict(cls, data: dict[str, Any]) -> CronRunRecord: return cls( - run_at_ms=_required_store_int(get_camel_snake(data, "runAtMs", "run_at_ms", 0)), + run_at_ms=_store_int(get_camel_snake(data, "runAtMs", "run_at_ms", 0)), status=data["status"], - duration_ms=_required_store_int( - get_camel_snake(data, "durationMs", "duration_ms", 0) - ), + duration_ms=_store_int(get_camel_snake(data, "durationMs", "duration_ms", 0)), error=data.get("error"), ) @@ -155,8 +153,8 @@ class CronJob: schedule=CronSchedule.from_store_dict(data["schedule"]), payload=CronPayload.from_store_dict(data.get("payload") or {}), state=CronJobState.from_store_dict(data.get("state") or {}), - created_at_ms=int(get_camel_snake(data, "createdAtMs", "created_at_ms", 0)), - updated_at_ms=int(get_camel_snake(data, "updatedAtMs", "updated_at_ms", 0)), + created_at_ms=_store_int(get_camel_snake(data, "createdAtMs", "created_at_ms", 0)), + updated_at_ms=_store_int(get_camel_snake(data, "updatedAtMs", "updated_at_ms", 0)), delete_after_run=bool( get_camel_snake(data, "deleteAfterRun", "delete_after_run", False) ), diff --git a/tests/cron/test_cron_service.py b/tests/cron/test_cron_service.py index 83a605e3..8ef534e1 100644 --- a/tests/cron/test_cron_service.py +++ b/tests/cron/test_cron_service.py @@ -1032,8 +1032,8 @@ def test_load_jobs_accepts_null_run_history_ms(tmp_path) -> None: {"runAtMs": None, "status": "ok", "durationMs": None}, ], }, - "createdAtMs": 0, - "updatedAtMs": 0, + "createdAtMs": None, + "updatedAtMs": None, } ], } @@ -1046,3 +1046,5 @@ def test_load_jobs_accepts_null_run_history_ms(tmp_path) -> None: assert jobs[0].state.run_history[0].run_at_ms == 0 assert jobs[0].state.run_history[0].duration_ms == 0 assert jobs[0].state.run_history[0].status == "ok" + assert jobs[0].created_at_ms == 0 + assert jobs[0].updated_at_ms == 0