Skip to content

docs: timezone in schedules, time to next run, short last check on scheduled refreshes and tasks (CUB-5559) - #12283

Merged
mngr merged 1 commit into
masterfrom
docs/cub-5559
Oct 17, 2026
Merged

mngr merged 1 commit into
masterfrom
docs/cub-5559

Conversation

@mngr

@mngr mngr commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Depends on cubedevinc/cubejs-enterprise#16573. This page describes that PR's behaviour and must not merge before it.

Summary

Updates the docs for the schedule-clarity change on scheduled refreshes and scheduled tasks. The branch was rebuilt on master after #12258 (CUB-5556: the hover Edit button, the ⋯ shown on hover, the viewer-only Subscribe column) merged. Its wording on scheduled-refreshes.mdx is kept as merged.

  • Scheduled Refreshes (scheduled-refreshes.mdx)
    • Timezone: the picker lists every IANA zone with its UTC offset, and you can search it by name or by offset. The old "common timezones … otherwise UTC" text was already wrong on master: TimezonePicker offers 424 zones, and getBrowserTimezone falls back to UTC only for a zone the runtime can't resolve.
    • Sidebar card, with its lines listed in the card's order:
      • the schedule label with its zone ("Daily at 9:00 AM UTC", "Hourly at :05 UTC", a custom cron as written plus the zone), cut with "…" and shown whole on hover;
      • a Condition: line, which used to read "Alert:";
      • Next run in its largest unit only: "in 25 minutes", "in 7 hours", "in 16 days". Hours and days round to the nearest; minutes count down whole. A time already past reads "due now" or "due 3 hours ago". Hovering shows the line, with the date and time under it in your zone, naming the zone ("Oct 17, 2026, 11:00 AM GMT+1");
      • Control values above Notification;
      • a Last check line.
    • Scheduled refreshes tab:
      • new Condition and Last check columns;
      • columns listed in on-screen order;
      • the Schedule column no longer carries the alert summary;
      • Next run in one unit, with the line and the date and time on hover;
      • a cut Dashboard title shows whole on hover;
      • a cut Last check shows the whole line on hover, with the full check sentence under it;
      • the Schedule sort order: frequency, then day, then the time of day as written in each schedule's own zone, then the zone. Times in different zones are not converted.
  • Data Alerts (data-alerts.mdx): rewrote "Following an alert in the sidebar" for the short last-check line ("Last check: 3 minutes ago, Count increased by 2.7%, notified"). It covers:
    • what each rule reads, and the five outcomes;
    • the age in its largest unit;
    • the hover: the line, with the full sentence under it, its time naming the zone;
    • the table column, and what non-creators see.
  • Scheduled Tasks (scheduled-tasks.mdx):
    • list columns: on/off switch, Name, Description, Schedule with zone, Condition, Next run, Notifications, Last check. There is no Status column. Next run is in one unit, or "due …" once past;
    • which columns sort;
    • how the switch behaves: disabled on manual tasks, absent on a task shared read-only, disabled while saving;
    • the detail page's Repeats line, with its timezone.
  • Google Sheets deliveries (google-sheets-deliveries.mdx): the list and the dialog name each cron with the delivery's timezone. A cut schedule shows whole on hover.

What I verified against the code

Checked against the feature branch (mentor/cub-5559-improve-schedule-clarity-in-scheduled, HEAD 2bf1a42753) and the round-4 hand-off walk on staging-mngr-9 (deployment 1259, dashboard VOXtdT7bUW6R, handoff-walk-r4.log):

  • Labels: the walk printed "Daily at 9:00 AM UTC", "Daily at 9:00 AM America/New_York", "Weekly on Monday at 9:00 AM UTC", "Monthly on day 1 at 8:00 AM UTC", "Hourly at :05 UTC" and "0 9 * * 1-5 UTC". The long-zone chip is cut and shows the whole label on hover, and the badge reads "Alert" in full.
  • Condition prefix: the walk printed "Condition: Count is above 1 · Orders count". The table cell has no prefix ("Count is above 1 · Orders count").
  • Next run: formatDuration in use-schedule-labels.ts (1fb26501e1) gives minutes below an hour, then rounded hours below 24, then rounded days. formatTimeUntil (7add8d07d5) gives relative.soon "in less than a minute", relative.dueNow "due now" and relative.dueAgo "due {{duration}} ago". formatDateTime uses timeZoneName: 'short'.
    • Walk, sidebar: "Next run: in 8 hours", "in 2 days", "in 29 days", and "in 22 minutes", which read "in 21 minutes" 62 s later. Hovering shows ["Next run: in 8 hours", "Oct 17, 2026, 11:00 AM GMT+1"].
    • Walk, tasks: "in 15 days", hover "Nov 1, 2026, 8:00 AM GMT+0".
    • Both tables use the same NextRunTime (ScheduledTaskListCells.tsx:41).
  • Card order: walk AC-5 printed Condition < Next run < Control values < Notification < Last check.
  • Last check: the walk read "less than a minute ago, Count was 40,000, still met, not notified again". Hovering shows that line, with "Last check Oct 17, 2026, 3:08 AM GMT+1: Count 339 (2026-09). Previous: 330 (2026-08), +2.7%. Condition not met." under it (b5c204e8ca relativeTimeTooltip). A non-creator reads "1 minute ago, still met, not notified again", with "values not shown, as it ran with the access of the schedule's creator" on hover.
  • Refreshes columns: walk headers "(switch) · Dashboard · Schedule · Condition · Next run · Control values · Notifications · Last check". A viewer also sees "Subscribe". The Last check cell is ellipsized inside its own cell (leaf right 1365 ≤ cell right 1380). The Dashboard title is a kit TextItem (b5c204e8ca).
  • Sort: scheduleSortKey (schedule.ts) is rank|day|minutes-of-day|zone. The walk's ascending order: Hourly :05, Hourly :30, Daily 7:00 AM, three 9:00 AM schedules (America/Argentina, America/New_York, UTC), 10:00 AM, 1:00 PM, Weekly Mon, Weekly Wed, Monthly day 1, Monthly day 15, then 0 9 * * 1-5. On the tasks list, Manual sorts last.
  • Tasks list:
    • Walk headers: "(switch) · Name · Description · Schedule · Condition · Next run · Notifications · Last check".
    • Cells: "Paused", "Manual", "Inbox" or "—", "Not checked yet", "11 minutes ago, Count increased by 2.7%, notified" / "…, met" / "…, still met, not notified again".
    • Non-creator rows show no reading and no switch.
  • Task switch:
    • On a manual task it is disabled, with the tooltip "A manual task runs only when started by hand, so it has no schedule to turn on or off".
    • On a daily task its tooltip reads "Pause this task: it stops running on its schedule". Pressing it shows "Paused", which stays after a reload; pressing it again shows "in 7 hours".
  • Detail page Repeats: walk "Daily at 9:00 AM UTC".
  • Deliveries: the walk row read "Daily at 9:00 AM Europe/Berlin, Weekly on Monday at 8:00 AM Europe/Berlin". The schedule cell is a kit TextItem (report-delivery-cells.tsx:200, dac983b035).

Feature PR: https://github.com/cubedevinc/cubejs-enterprise/pull/16573
Linear: https://linear.app/cube-d3/issue/CUB-5559/improve-schedule-clarity-in-scheduled-refreshes-and-tasks

@mngr
mngr requested a review from keydunov as a code owner October 16, 2026 04:14
@mintlify

mintlify Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
cubed3 🟢 Ready View Preview Oct 17, 2026, 2:23 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

@github-actions github-actions Bot added the docs Issues that require a documentation improvement label Oct 16, 2026
@claude

claude Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @mngr's task in 1m 17s —— View job


Looks good overall, no blockers: 0 high, 1 medium, 1 low. Merge only after cubedevinc/cubejs-enterprise#16573, as the description says.

Review details
  • Read diff and changed files
  • Review docs accuracy / style
  • Check prior review threads
  • Post findings

Findings

Severity Location Issue
Medium docs-mintlify/docs/explore-analyze/data-alerts.mdx:229 (→ :241) ### When a check can't run still says "The last-check line says why", but the visible line now only reads "could not check". The reason appears on hover only. Fix this →
Low docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx:272-277 The Schedule sort paragraph is wordy. I left an inline suggestion that cuts it to 4 lines.

Checked, no issues

  • Every anchor the new text links to exists: #managing-tasks, #task-detail-page, #getting-notified-when-a-run-finishes, #conditional-tasks, #viewing-all-scheduled-refreshes, #following-an-alert-in-the-sidebar, #managing-schedules, #timezone, and /docs/inbox.
  • No old strings are left anywhere in the docs ("common timezones", "At 09:00 AM", "Alert: " in the sidebar).
  • The new task-list text agrees with the rest of scheduled-tasks.mdx:
    • The switch's behaviour matches the creator/admin-only permissions under Managing tasks.
    • Next run reading "Paused" matches the Paused tag on the detail page.
    • Only the creator sees the values in Last check, as on the detail page.
  • I didn't check the UI strings (timezone search by "GMT-5", the five outcome labels, the hover sentence) against the code: the feature lives in cubejs-enterprise, which isn't in this checkout. I relied on the verification notes in the PR description.

Review threads

The listing returned 0 of my threads, so none were resolved or re-affirmed.

@github-actions github-actions Bot added the pr:community Contribution from Cube.js community members. label Oct 16, 2026
Comment thread docs-mintlify/docs/explore-analyze/data-alerts.mdx Outdated
Comment thread docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx Outdated
@claude

claude Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @mngr's task in 1m 26s —— View job


Review: looks good apart from wording fixes: 0 high, 1 medium, 2 low

Details
  • Read diff and changed files
  • Review docs for accuracy/consistency
  • Handle prior review threads
  • Post review

Inline findings

Severity Location Issue
Medium docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx:273 Says the Schedule column "sorts by when each schedule runs", but the sort key compares wall-clock time before timezone. So "9:00 AM America/New_York" sorts ahead of "10:00 AM UTC", even though it runs later. scheduled-tasks.mdx:53 repeats the claim.
Low docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx:76 The text says each zone shows its "UTC offset", but the search example is "GMT-5". The example should use the format the picker shows.
Low docs-mintlify/docs/explore-analyze/scheduled-tasks.mdx:48-50 "detail page tells the whole check" is awkward wording, and the sentence is overlong.

Checked and fine

  • All new anchors exist: #managing-tasks, #task-detail-page, #getting-notified-when-a-run-finishes, #conditional-tasks, #viewing-all-scheduled-refreshes, #following-an-alert-in-the-sidebar. /docs/inbox exists too.
  • "A task shared with you has no switch" matches the existing statement that sharing is view-only (scheduled-tasks.mdx:178).
  • The sidebar card order matches the order the PR description gives (Condition → Next run → Control values → Notification → Last check). data-alerts.mdx now says "the card's last line", which agrees with that order.
  • The tasks list says only the creator sees what a check read. That matches the detail page text at scheduled-tasks.mdx:267-270, admins included.

Not verifiable from this repo: UI strings such as "met, nothing sent", "Every run" and "Not scheduled", which live in cubejs-enterprise#16573. I relied on the PR description's walk-through for those.

Review threads: the listing returned 0 of my threads. I resolved none and re-affirmed none (no prior threads).

Comment thread docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx Outdated
Comment thread docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx
Comment thread docs-mintlify/docs/explore-analyze/scheduled-tasks.mdx
@claude

claude Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @mngr's task in 1m 16s —— View job


Looks good to merge once cubedevinc/cubejs-enterprise#16573 lands. 0 high, 0 medium, 2 low.

Review details
  • Read the diff and changed pages
  • Check claims against the docs and PR description
  • Resolve stale threads / dedupe findings
  • Post review

Findings

Low

  • docs-mintlify/docs/explore-analyze/scheduled-tasks.mdx:48-50: "the task's detail page tells the whole check" reads oddly, and the bullet is about twice as long as the ones next to it. I posted a suggestion that rewords it.
  • docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx:262: the Last check column doesn't say what it shows for an alert that hasn't been checked yet. The sidebar reads "Last check: not run yet" and the tasks list reads "Not checked yet". On this page only "—" is documented, and only for a schedule with no alert.

Checked

  • All new anchors and links resolve: #managing-tasks, #conditional-tasks, #task-detail-page, #getting-notified-when-a-run-finishes, /docs/inbox, #viewing-all-scheduled-refreshes, #managing-schedules, #timezone, and the new [ref-following-alert] → data-alerts#following-an-alert-in-the-sidebar.
  • The pages agree with each other. Refreshes show "Disabled" and tasks show "Paused". The Condition summary has no prefix in the table and "Condition:" on the card. The outcome wording in data-alerts.mdx matches the examples on the other two pages. The removed Status column on the tasks list isn't mentioned anywhere else (the detail page's status tag is a separate thing and is still correct).
  • The sort description after 346beeb (time as written in each schedule's own zone, then zone) matches the scheduleSortKey behaviour described in the PR body.
  • I couldn't check UI strings against cubejs-enterprise#16573 from here; the review takes the PR body's checks against that branch at face value.

Review threads

The listing returned 0 of my own threads, so there was nothing to resolve or re-affirm.

Comment thread docs-mintlify/docs/explore-analyze/scheduled-tasks.mdx
Comment thread docs-mintlify/docs/explore-analyze/scheduled-refreshes.mdx
@claude

claude Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @mngr's task in 1m 0s —— View job


LGTM. No correctness issues found: 0 high, 0 medium, 2 low (not posted inline).

Review details

Checks

  • Read diff (4 files, single commit 3097ded)
  • Checked anchors, links and cross-page consistency
  • Resolved and deduplicated prior review threads
  • Posted review

Findings

All the new anchors resolve: #managing-schedules, #viewing-all-scheduled-refreshes, #task-detail-page, #managing-tasks, #getting-notified-when-a-run-finishes, the new [ref-following-alert] → data-alerts#following-an-alert-in-the-sidebar, and /docs/inbox. Labels, the card order, the column order, the sort key and the switch behaviour match what the PR body says was verified against cubedevinc/cubejs-enterprise#16573. I can't read the enterprise code from here, so I didn't re-check the UI strings against the source.

You said only medium- and high-severity fixes go into this PR, so these two low-severity editorial notes are not posted inline:

  • docs-mintlify/docs/explore-analyze/scheduled-tasks.mdx:35-43: the Next run bullet links to the Scheduled refreshes cards and also repeats their whole rule (largest unit, "due now" / "due … ago", the hover). Keeping only the link and the task-specific states ("Paused", "Manual", "Not scheduled") would say it once.
  • docs-mintlify/docs/explore-analyze/scheduled-tasks.mdx:27 vs :215: the same control is called "Enable/disable toggle" in the column list and "switch" under Managing tasks.

Review threads

The listing returned 0 of my own unresolved threads (no prior threads), so nothing was resolved or re-affirmed.

@mngr
mngr merged commit 6155906 into master Oct 17, 2026
17 checks passed
@mngr
mngr deleted the docs/cub-5559 branch October 17, 2026 06:16
mngr added a commit that referenced this pull request Oct 23, 2026
…uns (CUB-5670) (#12266)

Depends on cubedevinc/cubejs-enterprise#16532 (and its base
cubedevinc/cubejs-enterprise#16531): do not merge before them. Also
merge it together with, or after, the cube-js/cube API reference sync
for the first `@cube-dev/platform-client` release that carries
`notification` (cubedevinc/cubejs-enterprise#16532 adds the field and
rewrites the `condition` descriptions in
`packages/platform-client/src/schema.ts`): until that sync,
`docs-mintlify/api-reference/api.yaml` has no `notification` field and
still says the creator gets an inbox row only with `notificationEnabled:
true`, which this page's Platform API section contradicts.

## Summary

A scheduled task now notifies chosen people, user groups and Slack
channels, by Inbox, Email and Slack together, instead of only its
creator in the inbox. Rebased on master after #12283
(CUB-5559: list columns, Next run, Last check), #12307 (the
**Manage all scheduled tasks** permission), #12309 (the
task's **Agent**) and #12368 (data-model access in scheduled
runs, a section this PR does not touch); their merged wording is the
base. This PR updates:

- `docs-mintlify/docs/explore-analyze/scheduled-tasks.mdx`
- *Where to find it*: the list's **Notifications** column now says where
a task's notifications go ("Inbox, Email · 3 people, 1 group · #sales,
#finance-alerts", or "Nobody is notified"), and links the renamed
section.
- *Anatomy of a task*: the **Notify me when a run finishes** toggle
becomes the **Notify** section.
- *Conditional tasks*: recipients other than the creator, and Slack, are
told the condition started to hold without the figures. A task with a
condition must notify someone: the dialog's **Create** (or, when
editing, **Update**) button stays disabled and says why, the agent
refuses, and the Platform API refuses when the request sets
`notification` (a request without that field is saved, as before).
- *Managing tasks*: anyone the task is shared with can open its runs'
threads, view-only (previously: sharing the task did not share its
threads).
  - *Task detail page*: a **Notifies** line, as in the list's column.
- *Last check*: the example of a task that notifies nobody is one
created through the Platform API without a `notification` field.
- *Getting notified when a run finishes* is rewritten as *Notifying
people when a run finishes*: people and groups (expanded when the run
finishes, one message per person), **Send by** Inbox / Email / Slack
(Inbox and Email go to everyone picked; one or more Slack channels), the
creator picked by default, what each notification carries, sharing on
save of a new pick (dialog, agent and Platform API alike), who a run
reaches (the creator, plus people who can open the task and read its
deployment), and the two ways a picked person is skipped and marked
**Not shared: won't be notified** (their share was removed in the
**Share** dialog, or they can't read the deployment), notifications
going to recipients whoever runs the task, email unsubscribe, a failed
run reaching only the creator, and the agent and Platform API.
- The agent paragraph of that section: channels belong to the whole
task, so asking the agent to notify one more person by inbox turns
**Inbox** on for everyone the task notifies, and the agent says so.
- *Managing tasks from chat* and *with the Platform API*: the new
`notification` field and its caps; `notificationEnabled` deprecated.
- `docs-mintlify/docs/inbox.mdx`: the Scheduled task run row's "Who gets
it", the figures shown only in the creator's notification, email/Slack
from a task, and the anchor rename.

## Verified against the code (feature branch HEAD `e22eb3290b`)

- Labels are the en-US keys in
`packages/console-ui/src/i18n/locales/en-US/scheduledTasks.json`:
`notifyLabel` "Notify", `notifyRecipientsLabel` "People and groups",
`notifyChannelsLabel` "Send by", `notifyRecipientNotShared` "Not shared:
won't be notified", `notifySlackChannelsDescription` "Slack posts once
to each channel. Inbox and Email go to the people above.",
`summary.notifiesNobody` "Nobody is notified", `detail.notifies`
"Notifies".
- The list's Notifications cell and the detail page's Notifies line both
render `useNotificationSummary` (`task-notification.ts`;
`ScheduledTaskListCells.tsx`, `ScheduledTaskInstructions.tsx`); Inbox
drops out of it when the workspace's inbox is off
(`deliveredNotification`). The hand-off walk on staging-mngr-7 read
"Inbox, Email · 4 people, 1 group" and "Inbox · 3 people, 1 group".
- The list's Last check reads "notified" when a crossing reaches anyone,
not only the creator (`taskOutcome(check, notifiesAnyone)`).
- The condition rule: `ScheduledTaskService.assertConditionNotifies`
holds a save only when it sends `notification` (`sendsNotification`) or
the agent's update asks for it; the agent's create tool always sends
`notification` (`CreateScheduledTaskToolFactory.ts:112`).
- Who a run reaches:
`AiEngineerController.notifyScheduledTaskRecipients` expands groups at
send time, de-duplicates, keeps only the creator on a failed run, and
skips any non-creator for whom `AiEngineerService.canViewScheduledTask`
(a ScheduledTask read grant or admin, plus deployment read) is false;
Inbox is sent only with the tenant's `useNotificationInbox` on.
- Caps: `NOTIFICATION_CAPS = { userIds: 1000, groupIds: 200,
slackChannels: 50 }`
(`packages/ai-engineer/src/dto/scheduled-task.ts:290`).
- Sharing on pick: `ScheduledTaskService.grantRecipientShares` runs on
every create and update (the dialog, the agent's
`createTask`/`updateTask` tools and the REST controller all call the
service), sharing only recipients the save ADDS and only if not already
shared, so a share revoked in the Share dialog is not restored by a
later save. The "Not shared" mark for a user is
`recipientUserIdsWithoutAccess`, console-server's
`findUsersWithoutScheduledTaskAccess` = `canViewScheduledTask` (task
read grant or admin, AND deployment read), so a shared user who cannot
read the deployment is marked too (PLAN AC-7d); a group is marked when
it has no group grant and no organisation grant.
- Channels are task-wide on the agent's path too:
`NOTIFY_ARGUMENTS_DESCRIPTION`
(`packages/ai-engineer/src/services/langgraph/tools/scheduled-task-recipients.ts:29`,
"for the whole task") and the update tool's `channelsChanged` note
(`channelChangeNote`, same file, "Channels are shared by everyone this
task notifies … Tell the user."). The r3 hand-off walk on staging-mngr-7
asked the agent to also notify a second person in the inbox on an
Email-only task: the stored channels became Inbox + Email for both, and
the agent's reply said so.
- The two feature commits since the last docs pass (`7e097cebb6` Slack
picker error handling, `1257d35839` a failed task email answers 503)
change nothing the pages describe.
- The task dialog's submit button reads `dialog.submitCreate` "Create"
on a new task and `dialog.submitUpdate` "Update" when editing
(`ScheduledTaskDialog.tsx:203`); the r4 hand-off walk on staging-mngr-7
read "Create disabled" with the red line and Create's tooltip
`conditionNeedsNotification`. The page used to call it **Save**; it now
names both.
- The feature commits since the last docs pass (`8904d17d1e` keeps the
dialog's 12 px field gap around the condition switch and the Notify
section, which Igor flagged after the hand-off; the Slack OAuth listener
refactor `773666a9d9`/`baed62646a`; `50546100b7` drops a removed kit
prop; `e149367c86` a failed task email answers 503) change no behaviour
the pages describe. The hand-off, re-posted for the spacing fix, says
nothing else changed.
- A new task in the dialog starts with the creator picked and Inbox on;
a task created by the agent or the API without a `notification` notifies
nobody.

Feature PR: cubedevinc/cubejs-enterprise#16532
Linear:
https://linear.app/cube-d3/issue/CUB-5670/notify-other-people-about-scheduled-task-runs

---------

Co-authored-by: Gleb <gleb@Glebs-MacBook-Air-2.local>
mngr added a commit that referenced this pull request Oct 23, 2026
…ecks (CUB-5218) (#12306)

Depends on cubedevinc/cubejs-enterprise#16509 and its part PRs
cubedevinc/cubejs-enterprise#16507 (chat tools),
cubedevinc/cubejs-enterprise#16508 (public API `alert`), and
cubedevinc/cubejs-enterprise#16825 (sidebar status retry). **Do not
merge this before cubedevinc/cubejs-enterprise#16509 merges.** Before
that, the page describes % change and Anomaly on a KPI, which the
product does not yet offer.

## Summary

Data alerts' **% change** and **Anomaly** rules now work on a chart or
KPI with no time dimension. On such a chart the alert remembers the
value each check reads and compares with those values: % change with the
previous check, Anomaly with the normal range of the earlier checks,
once there are 8. The chat agent can list, create, change and delete a
dashboard's scheduled refreshes together with their alert. The public
notifications API takes an `alert` field.

- `docs/explore-analyze/data-alerts.mdx`
- **% change** / **Anomaly**: what each compares with on a chart with
and without a time dimension, and the "vs the previous period" / "vs the
previous check" suffix.
- **Which charts support which rule**: a chart without a time dimension
now supports every rule type (it used to say Threshold only). It quotes
the dialog's checks line.
- **What an alert checks**: the single-value paragraph names the
comparison with previous checks.
  - New **Comparing with previous checks** section:
- what is remembered: the last 30 checks; Threshold alerts and time
charts remember nothing;
- the first check's "no earlier check" line and the Anomaly "Needs 8
earlier checks, has N." count (only the creator sees the count; anyone
else reads "Needs 8 earlier checks.");
    - Run now is a check, compared and remembered like a scheduled one;
- what remembers nothing: no number read, or a fire that reached no one;
- what keeps the remembered values and what discards them; republishing
keeps them.
- **When an alert notifies**: turning the schedule off still resets the
notify-once state, but keeps the remembered values.
- **The notification**: the email's previous-check and earlier-checks
lines, and a check-based Slack sentence.
- **Following an alert in the sidebar**: rebased onto master's CUB-5559
rewrite (#12283, the short "Last check: 3 minutes ago, …"
line with the full check on hover), kept as merged. Added: the "vs the
previous check" ending of the "Condition:" summary, and the hover's
"Previous check …" / "Normal range of the earlier checks" lines on a
chart without a time dimension, and that after **Run now** the open card
shows the new check by itself (a run can take a few minutes).
- **When a check can't run**: the check-based reasons, and that such a
check still remembers a value it read.
- New **Managing alerts from chat** and **Managing alerts through the
API** sections.
**Managing alerts from chat** says the agent never makes an alert on a
chart of a published dashboard into a scheduled task with a condition:
the alert belongs to that dashboard's scheduled refresh.
- `docs/explore-analyze/scheduled-refreshes.mdx`:
- **Managing schedules** → **Next run**: until an enabled schedule's
status has been read (loading, or the read failing), a placeholder
stands in for **Next run** and **Last check**, and the card asks again
every few seconds.
- **Managing schedules** → **Schedule**: a custom cron that matches no
preset is now described in full ("At 09:00 AM, Monday through Friday
UTC"), not shown as written. This sentence was made false by
cubedevinc/cubejs-enterprise#16776 (CUB-5994, already on master:
`describeSchedule` → `cronSentence`, cronstrue; `node -e
"require('cronstrue').toString('0 9 * * 1-5')"` → "At 09:00 AM, Monday
through Friday"), corrected here as an adjacent defect.
  - new **Managing schedules from chat** section, covering:
  - what the agent can do;
- email to Cube users only (Slack, groups and control values stay in the
dialog);
  - Edit/Manage needed to change a schedule;
- last-check values shown to the creator only; recipients told only to
those who can edit the schedule, anyone else told they are hidden;
  - no tools in published-dashboard or embedded chat.
- `docs/explore-analyze/scheduled-tasks.mdx` → **Managing tasks from
chat**: when data alerts are on, an alert on a chart of a published
dashboard is not a task; it belongs to that dashboard's scheduled
refresh, and the agent doesn't create a task for it.
- `api-reference/api.yaml`: mirrors the regenerated public spec's change
only:
  - the `DataAlertRule` / `DataAlertRuleInput` schemas and their enums;
  - `alert` on `NotificationDto` and `UpdateNotificationInput`;
  - the create and update notification descriptions.

I produced it by running `scripts/extract-api.mjs` on master's
`open-api-spec-public-v3.1.yaml` and on the head's, then applying the
difference (6 hunks). That keeps it independent of master's other
unreleased spec changes, which `api.yaml` (synced per platform-client
release) does not carry yet.

## Verified against the code

- **Form.** On the round-2 hand-off walk (staging-mngr-6,
`handoff-run-r2.log`, 2026-10-19; unchanged on the round-3 and round-4
walks, `handoff-run-r3.log` / `handoff-run-r4.log`, 2026-10-21/22), a
KPI with no time axis showed:
  - all three rule-type tabs enabled;
  - the suffix "vs the previous check";
- the checks line "Compares with the values this alert read on its
previous checks.";
  - the anomaly hint;
  - no checks line under Threshold.

  The rule saved as `timeColumn: null`, `grain: null`.
- **Comparison.** `evaluateAgainstChecks`
(`ai-engineer/.../alerts/evaluate-alert-rule.ts`):
  - % change takes the last remembered point;
  - a previous 0 gives `previous-zero`;
- Anomaly needs `DATA_ALERT_ANOMALY_MIN_POINTS` (8) and uses
`medianMadBand` over the remembered values.
- **What is remembered.** `alert-history.ts`:
- `checkPointOf` remembers only a check-based verdict that read a
number;
  - `appendCheckPoint` keeps `DATA_ALERT_CHECK_HISTORY_MAX` = 30;
- `historyFor` / `keepsHistory` key on rule id, series and
`filterParams`.

`prepareDataAlertRule` keeps the rule id unless `dataAlertConditionKey`
changes (chart, report, measure, type, direction, percent).
- **Live checks** (walk log):
- first check: line "Last check: less than a minute ago, could not
check", hover "… could not check. There is no earlier check to compare
with yet. Nothing sent.";
- Anomaly: "Needs 8 earlier checks, has 0." and then "has 1." for the
creator; "could not check. Needs 8 earlier checks. Nothing sent." for a
non-creator on the same card (round-3 walk, run 4452);
- after Run now with the sidebar left open, the card showed the new
check with no reload; the round-3 walk measured 21–224 s from press to
card, hence "a run can take a few minutes";
- after republishing the KPI: line "Last check: less than a minute ago,
Count decreased by 50%, notified", hover "Last check Oct 19, 2026, 3:05
PM GMT+1: Count 20,003. Previous check Oct 19, 2026, 3:04 PM GMT+1:
40,000, -50%. Condition met, notified." This shows that republishing
keeps the remembered values;
  - after a cron edit the last check is unchanged;
- summary "Condition: Count decreases by ≥ 10% vs the previous check ·
Orders count".

Pause and resume keeping the values: AC-5c,
`verify-5-kept-through-edit-and-pause-has-3.png`.
- **Email and Slack.** The en-US email keys `alertPreviousCheckValue`,
`alertNormalRangeOfChecks` and `alertComparedWithPreviousChecks`
(cloud-router). The Slack sentence comes from `alertStatement`'s `basis
=== 'checks'` branch; its format is pinned by
`alert-notification.spec.ts`.
- **Sidebar strings.** en-US `creatorMode.json`: `summary*Checks`,
`lastCheckPreviousCheck`, `lastCheckBandChecks`, `reasonNoEarlierCheck`,
`reasonTooFewChecks`, `reasonPreviousCheckZero`.
- **Chat tools.** `DashboardScheduledRefreshToolsFactory.ts`:
- email to `recipientUserIds`, or the current user when none are named;
no Slack, groups or control values;
- bound when `useScheduledRefreshes`, which `AiEngineerService` sets off
for an embed session;
- stripped from published-dashboard chat through
`publishedDashboardUnsafeTools`;
  - writes need `WorkbookEdit` (`verify-11-read-only-user-refused.png`);
  - list values are withheld for a non-creator (`alertCheckForViewer`);
- a caller who cannot edit the run gets `recipientsWithheld: true`
instead of a recipient list (`describeRecipients`; console-server's
`serializeScheduledRun` nulls the ids unless `viewer.canEdit`), and the
description says never to report that as no recipients. Round-3 walk:
the non-creator's chat reply named no "no recipients".
- **Status placeholder.** `NextRunCell` / the last-check cell render
`Placeholder` while `run.isEnabled && run.isStatusPending &&
!run.hasStatus`; a failed read leaves the run pending and joins the 5 s
status poll (`use-scheduled-refreshes.ts`,
cubedevinc/cubejs-enterprise#16825, spec AC-6g in
`ScheduledRefreshSidebar.spec.tsx`).
- **Run now on the open card.** `use-scheduled-refreshes.ts` keeps
polling a Run now's status until it reports the run finished, then up to
`RUN_NOW_CHECK_WAIT_MS` (60 s) more for the stored check.
- **Chat routing of a dashboard alert**
(cubedevinc/cubejs-enterprise#16507, `730cdb4add`):
- `createDashboardScheduledRefresh`'s description says an alert on a
published dashboard's chart is always set up there;
- `createScheduledTask`'s says a task condition watches a measure
outside any dashboard. It adds that clause only when
`useScheduledRefreshes && useDataAlerts`, hence "when data alerts are
turned on";
- the Chassis `schedule-tasks` skill says such an alert "is a scheduled
notification on that dashboard, not a task" and points to the
dashboard's schedule settings. So the page promises "never a task", not
that the agent always creates the refresh itself;
- round-4 hand-off walk (`handoff-run-r4.log`, [WALK 12], 2026-10-22):
"Email me when the Orders count KPI … goes above 1000. Check every day
at 9:00 UTC." made `createDashboardScheduledRefresh` 1 call and
`createScheduledTask` 0. It created refresh 5050 with a
`threshold`/`gt`/1000 alert on the KPI (`timeColumn: null`), and its
card read "Condition: Orders Count is above 1,000 · Orders count".
- **Public API.** The regenerated `open-api-spec-public-v3.1.yaml` on
the feature branch.

Feature PR: cubedevinc/cubejs-enterprise#16509
Linear:
https://linear.app/cube-d3/issue/CUB-5218/data-alerts-percent-change-and-anomaly-rules-for-kpi-charts

---------

Co-authored-by: Gleb <gleb@Glebs-MacBook-Air-2.local>

This branch was successfully deployed

1 active deployment
staging - docs-mintlify — 3097ded6 Deployed Oct 17, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Issues that require a documentation improvement pr:community Contribution from Cube.js community members.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant