fix(cron): resolve lastRunStatus in cron list/show human output#93245
Conversation
cron list/show printed "idle" for a job whose status is ok/error/skipped when only lastRunStatus (the primary field) was set: formatStatus used `lastStatus ?? "idle"` and omitted lastRunStatus, diverging from computeStatus (the --json status resolver) whose JSDoc says it mirrors the human output. Delete the duplicate formatStatus and render via the canonical computeStatus. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
Codex review: needs maintainer review before merge. Reviewed June 15, 2026, 6:17 AM ET / 10:17 UTC. Summary PR surface: Source -8, Tests +35. Total +27 across 2 files. Reproducibility: yes. from source inspection: a job with Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Merge the narrow resolver consolidation after normal maintainer and CI gates so cron human and JSON status output share one canonical implementation. Do we have a high-confidence way to reproduce the issue? Yes from source inspection: a job with Is this the best way to solve the issue? Yes. Reusing AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 0314819f918a. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source -8, Tests +35. Total +27 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
…claw#93245) cron list/show printed "idle" for a job whose status is ok/error/skipped when only lastRunStatus (the primary field) was set: formatStatus used `lastStatus ?? "idle"` and omitted lastRunStatus, diverging from computeStatus (the --json status resolver) whose JSDoc says it mirrors the human output. Delete the duplicate formatStatus and render via the canonical computeStatus. Co-authored-by: ly-wang19 <[email protected]> Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…claw#93245) cron list/show printed "idle" for a job whose status is ok/error/skipped when only lastRunStatus (the primary field) was set: formatStatus used `lastStatus ?? "idle"` and omitted lastRunStatus, diverging from computeStatus (the --json status resolver) whose JSDoc says it mirrors the human output. Delete the duplicate formatStatus and render via the canonical computeStatus. Co-authored-by: ly-wang19 <[email protected]> Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
…claw#93245) cron list/show printed "idle" for a job whose status is ok/error/skipped when only lastRunStatus (the primary field) was set: formatStatus used `lastStatus ?? "idle"` and omitted lastRunStatus, diverging from computeStatus (the --json status resolver) whose JSDoc says it mirrors the human output. Delete the duplicate formatStatus and render via the canonical computeStatus. Co-authored-by: ly-wang19 <[email protected]> Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Summary
openclaw cron listandopenclaw cron showprintidlefor a job whose real status isok/error/skippedwhenever the job's state carries onlylastRunStatus(the primary field) and not the deprecatedlastStatusalias.The human-render helper
formatStatus(src/cli/cron-cli/shared.ts) resolved the status asstate.lastStatus ?? "idle", omittinglastRunStatus— while the siblingcomputeStatus(used for the--jsonstatusfield) and every other status resolver in the codebase usestate.lastRunStatus ?? state.lastStatus ?? "idle".computeStatus's own JSDoc claims it "mirrors the human-readable status shown bycron list/cron show" — butformatStatushad diverged from it.lastRunStatusis the canonical field;lastStatusis@deprecated(src/cron/types.ts).Root cause + fix
formatStatuswas a near-duplicate ofcomputeStatusthat was never updated whenlastRunStatusbecame the primary field. This change deletesformatStatusand routes both human-render call sites (thecron listStatus column and thecron showstatus:line) through the single canonicalcomputeStatus— one resolver, honoring the documented "mirror" contract. Net −8 LOC in source.Change Type
Linked Issue
Source-discovered (no existing issue/PR — verified). The human
cron list/cron showstatus now matches the--jsonstatusfield and the rest of the status-resolution code.Evidence
renders lastRunStatus (matching the --json status), not idle, when lastStatus is unsetbuilds a job withstate: { lastRunStatus: "ok" }(nolastStatus) and assertscron showprintsstatus: ok(notstatus: idle), thecron listStatus column showsok, andenrichCronJsonWithStatusagrees (status: "ok"). Onmainthe human render returnsidle, so the test fails without this patch. Full file: 29/29 tests pass (Node 22.22.1). oxlint + oxfmt clean;tsgo:coreclean.Real behavior proof
Behavior addressed:
cron list/cron showhuman output now shows a job's real run status (ok/error/skipped) when onlylastRunStatusis set, instead ofidle, matching the--jsonstatusfield.Real environment tested: local OpenClaw dev gateway (
gateway run --dev --auth none) on Node 22.22.1 (macOS), isolatedOPENCLAW_STATE_DIR/OPENCLAW_HOME. A real cron job was created, then given alastRunStatus-only state via acron.updatestate patch (allowed byCronJobStatePatchSchema), then rendered bycron show/cron listonmainvs this patch.Exact steps or command run after this patch:
Evidence after fix: live gateway terminal output for the same
lastRunStatus-only job, onmainvs this patch:Observed result after fix:
cron show/cron listreport the real status (ok) for thelastRunStatus-only job; before the patch they reportedidlewhile--jsonreportedok. Normal jobs (which dual-write both fields) are unaffected.What was not tested: a job reaching the
lastRunStatus-only state purely through the live scheduler (the runtime dual-writes bothlastRunStatusandlastStatus, so the divergence was reproduced by writing the canonical field alone via the supportedcron.updatestate patch — exactly the field shape the deprecated-alias migration moves toward).Security Impact
None — display/formatting consolidation only. No new permissions, secrets, network calls, or tool-exec surface.
Compatibility / Migration
Backward compatible. Output is unchanged for every job that has
lastStatusset (all normally-run jobs); only the previously-wrongidlerendering forlastRunStatus-only state changes, to the correct status.AI assistance
AI-assisted (Claude Code). Verified locally: 29/29 unit tests, oxlint clean, oxfmt clean,
tsgo:coreclean, plus the live before/after gateway proof above. Author understands the change.