# Schedule creation and suspension repair

Status: original source/fixture repair verified locally. A subsequent [real queue and Chromium walkthrough](schedule-live-walkthrough.md) verifies execution, recovery, pause and deletion. The sections below describe the original isolated fixture checks; no production deployment is pending for this review.

## Cause

The shared ScheduleManager created a schedule BaseModel without `isNew: true`. `requestQueueInstance.saveData` selects creation when there is no `sk`; the Mongo repository provider requires the explicit new-record marker and otherwise throws `create => Not a new metrics, please use update or set the new property`.

Separately, the schedule update handler cancelled existing jobs on update and then recreated them without checking the saved status. Start, end, and cron workers loaded the schedule but also ignored its status: a stopped schedule could dispatch its action and have its status overwritten as active/done. Repairing creation alone would therefore expose stopped schedules to execution.

## Exact changes

- `websitemint/packages/ui/src/components/schedule-management/schedule-manager.tsx`: new schedules include `isNew: true`; the existing owner linkage, input data, and default status are preserved.
- `appengine/src/sync/schedule-status.ts`: shared suspension predicate recognizes `stop`, `stopped`, `pause`, `paused`, `cancelled`, and `canceled`, ignoring capitalization and surrounding spaces. It leaves existing runnable statuses, including new/active/pending/unset, unchanged.
- `appengine/src/sync/commands/schedule-updated-handler.ts`: queue creation skips suspended records. The existing update path still cancels all three keyed jobs first, then checks the persisted record before creating replacements.
- `appengine/src/sync/queue-consumer/schedule.consumer.ts`: start, end, and cron handlers check the freshly loaded status before target actions, status/last-run writes, queue lookups, or successful-run activity. This also suppresses queued jobs that survive cancellation or were queued before the status changed.

Unrelated checkout changes were preserved. No course manuscripts or learner-review files were edited. Cron calculation and retry behavior were not changed.

## Reproducible verification

From the docs checkout:

```sh
node tutorials-plan/application-fixes/assets/schedules/verify.cjs
```

The durable [verifier](assets/schedules/verify.cjs) defaults to sibling `websitemint` and `appengine` checkouts; supply those two paths as arguments to override. It uses installed TypeScript and Nest common packages. It transpiles and executes the actual command handler/queue consumer; all repository, queue, activity, event, and provider boundaries are stubs. The UI test extracts and executes the actual ScheduleManager create handler with the Mongo provider's checked `isNew` precondition enforced at its fake save boundary. It does not run a browser or connect to Redis/Mongo.

All **98 checks passed**; [saved output](assets/schedules/verification.txt) includes:

- Negative controls that remove only the new checks/marker from the same source and reproduce the previous creation rejection, job recreation after Stop, and start/end/cron dispatch of a stopped message.
- Successful creation with the owner preserved; explicit Stop remains Stop, and failed saves leave the editor open.
- Every suspension spelling for simple/cron creation and update, including cancellation without requeue.
- All three workers skipping suspended records without target reads, message changes, status changes, false-success activity, or event dispatch.
- New/active/pending/unset legacy behavior; resuming a stopped schedule; re-reading a status changed after enqueue; and removed-record handling.

Full backend TypeScript validation passed with zero diagnostics:

```sh
cd /path/to/appengine
./node_modules/.bin/tsc --noEmit --incremental false --pretty false
```

`git diff --check` passed in both affected checkouts. The UI create-handler fixture passes; a full builder application typecheck/build was not run for this one-field change.

## Original test limits and subsequent acceptance

The subsequent local walkthrough exercises real execution, pause and deletion; see the linked live report. Production deployment is outside this review. The original fixture also tests resume scheduling.

Workers enforce the status they read at execution entry. This does not retract an action already underway or provide an atomic transaction between a concurrent Stop write and an external send. Existing stopped jobs can remain present until the usual update/cancellation path runs, but these workers skip their actions when the saved record is suspended. No production schedules were inspected, replayed, or modified in this repair.
