Skip to content

fix(coding-agent): record a cron task's status reason when it is created - #355

Merged
liuedcson merged 1 commit into
mainfrom
fix/cron-create-status-reason
Nov 10, 2026
Merged

liuedcson merged 1 commit into
mainfrom
fix/cron-create-status-reason

Conversation

@liuedcson

Copy link
Copy Markdown
Collaborator

Background

CronCreateOptions declares statusReason, and parsePersistedJob validates the
field when a record is loaded:

if (candidate.statusReason !== undefined && candidate.statusReason !== "session_missing") return undefined;

create() did not write it. Only update() did. The type therefore promised a
field that the create path silently dropped.

Found while verifying the merged desktop scheduled-task feature. Its migration
imports a task whose bound session is already gone as
{ status: "paused", statusReason: "session_missing" }, so the import relied on a
create-with-reason that did not persist it. The task still appeared paused, which
is why the symptom was a missing explanation rather than a wrong status — the
import path happens to write the store directly today, so nothing was visibly
broken, but any host using the documented option lost the field.

Fix

packages/coding-agent/src/features/step-cron.ts — write statusReason in
create() beside status:

...(options.status ? { status: options.status } : {}),
...(options.statusReason ? { statusReason: options.statusReason } : {}),

The guard mirrors status: an absent reason adds no field, and the record reader
still rejects any value other than session_missing.

Verification

  • pnpm exec vitest --run test/step-cron.test.ts: 60 passed (one new test).
  • The new test fails with the fix reverted and passes with it, so it pins the
    behaviour rather than restating the implementation: it creates a task with
    status: "paused" and statusReason: "session_missing", reloads the store, and
    asserts both fields survive.
  • tsgo -p tsconfig.json --noEmit: clean.
  • Biome check --error-on-warnings and the pre-commit guard set: pass.

Boundary

One field on one write path. No schema change, no migration, and no change to
update() or the reader.

`CronCreateOptions` declares `statusReason`, and the persisted-record reader
validates it, but `create()` never wrote it. Only `update()` did.

A host that imports a task whose bound session no longer exists creates it
already paused, with `statusReason: "session_missing"`, so the reason was dropped
on the one path that needed it. The task still showed as paused, which is why the
symptom was a missing explanation rather than a wrong status; the type promised a
field the write did not store.

The new test creates such a task, reloads the store, and asserts both the status
and the reason survive.
@liuedcson
liuedcson merged commit 7bcfbbd into main Nov 10, 2026
2 checks passed
@liuedcson
liuedcson deleted the fix/cron-create-status-reason branch November 10, 2026 07:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant