Skip to content

feat(reports): report schedules honor cron_expression + timezone#1991

Merged
os-zhuang merged 1 commit into
mainfrom
feat/report-schedule-cron-tz-1983
Jun 17, 2026
Merged

feat(reports): report schedules honor cron_expression + timezone#1991
os-zhuang merged 1 commit into
mainfrom
feat/report-schedule-cron-tz-1983

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #1983. Self-contained slice of ADR-0053 Phase 2.

What

sys_report_schedule has long carried cron_expression and timezone fields, but ReportService only ever advanced next_run_at by interval_minutes — both fields were stored and ignored (author-facing but runtime-dead). This activates them.

Scheduling now computes next_run_at from the cron expression (when present) in the schedule's timezone, via croner — the same library the job scheduler (CronJobAdapter) already uses. So "every weekday at 09:00 local" is finally expressible. interval_minutes remains the fallback.

Behavior

  • cron_expression wins over interval_minutes when set (the field's documented contract).
  • Evaluated in timezone (default UTC).
  • scheduleReport validates the cron eagerly and rejects an invalid one with VALIDATION_FAILED, instead of silently degrading at sweep time. A cron that later has no next occurrence is logged and falls back to the interval — it never throws into the dispatch sweep.
  • A shared nextRunAt() helper drives both the initial schedule and advanceSchedule.

The DB-polling dispatch model (next_run_at <= now sweep) is unchanged — only the next-run computation became cron-aware. This fits report-service's architecture far better than the in-process croner-job model, and works across multi-instance deployments.

Why self-contained

Report schedules run under a system context (no user), so the timezone source is the schedule's own timezone field — same model as sys_job. So this slice needs none of the reference-timezone resolver (#1978) and can land independently.

Testing

  • New: cron drives/overrides interval; honors timezone (09:00 America/New_York = 14:00Z); invalid cron → VALIDATION_FAILED; dispatchDue advances to the next cron occurrence.
  • Full @objectstack/plugin-reports suite green — 29 tests; DTS build + typecheck clean.
  • Updated the sys_report_schedule doc comment (no longer "reserved"). Changeset: minor (new capability).

🤖 Generated with Claude Code

sys_report_schedule has long carried `cron_expression` and `timezone`
fields, but ReportService only ever advanced next_run_at by
`interval_minutes` — both fields were stored and ignored. Scheduling now
computes next_run_at from the cron expression (when present) in the
schedule's timezone via croner — the same library the job scheduler uses —
so "every weekday 09:00 local" is expressible. interval_minutes remains the
fallback.

- cron_expression wins over interval_minutes when set (the field's
  documented contract); evaluated in `timezone` (default UTC).
- scheduleReport validates the cron eagerly → VALIDATION_FAILED on bad
  input, rather than silently falling back at sweep time. A cron that
  becomes unschedulable later is logged and falls back to interval; it
  never throws into the dispatch sweep.
- Shared nextRunAt() helper drives both initial schedule and advance.

DB-polling dispatch model unchanged; only the next-run computation is
cron-aware. Self-contained slice of ADR-0053 Phase 2 — report schedules
run under a system context, so the tz source is the schedule's own field,
independent of the reference-timezone resolver.

Tests: cron drives/overrides interval; honors timezone (09:00 ET = 14:00Z);
invalid cron rejected; dispatchDue advances to next cron occurrence. Full
plugin-reports suite green (29). Closes #1983.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 16, 2026 11:00pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling size/m and removed documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling labels Jun 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/platform-objects, @objectstack/plugin-reports.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-reports)
  • content/docs/concepts/setup-app.mdx (via @objectstack/platform-objects)
  • content/docs/guides/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-reports)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit d42004b into main Jun 17, 2026
15 checks passed
@os-zhuang
os-zhuang deleted the feat/report-schedule-cron-tz-1983 branch June 17, 2026 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ADR-0053 Phase 2 · Slice 6: activate report-schedule cron + timezone (liveness enforce)

1 participant