Skip to content

Fix automation timezone scheduling#3738

Merged
saddlepaddle merged 2 commits intomainfrom
fix-automation-timezone
Apr 25, 2026
Merged

Fix automation timezone scheduling#3738
saddlepaddle merged 2 commits intomainfrom
fix-automation-timezone

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Apr 25, 2026

Summary

  • compute automation RRULE occurrences using floating wall-clock dates, then convert once to the automation timezone so production UTC processes do not shift runs
  • format automation next/last run times in the automation timezone in desktop and CLI surfaces
  • validate IANA timezone inputs and avoid clearing the CLI target device when automations update omits --device

Verification

  • bun test packages/shared/src/rrule.test.ts
  • TZ=UTC bun test packages/shared/src/rrule.test.ts -t "recurrence timezone math"
  • TZ=America/Los_Angeles bun test packages/shared/src/rrule.test.ts -t "recurrence timezone math"
  • bun run --cwd packages/shared typecheck
  • bun run --cwd packages/trpc typecheck
  • bun run --cwd packages/cli typecheck
  • bun run --cwd apps/desktop typecheck
  • bunx @biomejs/biome@2.4.2 check packages/shared/src/rrule.ts packages/shared/src/rrule.test.ts packages/trpc/src/router/automation/schema.ts packages/cli/src/commands/automations/format.ts packages/cli/src/commands/automations/create/command.ts packages/cli/src/commands/automations/list/command.ts packages/cli/src/commands/automations/resume/command.ts packages/cli/src/commands/automations/update/command.ts 'apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx'\n\n## Follow-up\nExisting production automations whose next_run_at was already computed with the old logic should be recomputed from rrule, dtstart, and timezone after this deploy. This PR prevents new creates/updates/resumes and future cron advances from carrying the offset bug forward.

Summary by cubic

Fixes automation scheduling so runs occur at the intended local time, regardless of host timezone or UTC drift. Times now display in the automation’s timezone in both desktop and CLI.

  • Bug Fixes

    • Compute RRULE occurrences on floating wall-clock dates and convert once to real UTC in the automation timezone (stable across DST and host TZ).
    • Show Next/Last run in the automation timezone in desktop and CLI via formatDateTimeInTimezone; added CLI formatAutomationDate.
    • Validate IANA timezone names in the API; automations update no longer clears the target device when --device is omitted.
    • Formatting falls back to UTC for invalid or legacy timezone values; stabilized timezone formatting tests.
  • Migration

    • Recompute existing next_run_at from rrule, dtstart, and timezone after deploy.

Written for commit 00ea424. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Automation dates now display in the configured timezone across the desktop UI and CLI outputs (creation, listing, resume, sidebar).
  • Bug Fixes

    • Improved timezone validation to ensure only valid IANA timezone names are accepted.
    • Fixed device parameter handling in the update command to distinguish unset vs. null.
  • Tests

    • Added tests covering timezone-aware recurrence and DST behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

📝 Walkthrough

Walkthrough

Introduces timezone-aware formatting and RRULE behavior changes: adds formatDateTimeInTimezone and formatAutomationDate, converts RRULE processing to floating wall-clock DTSTART with explicit UTC conversion, updates CLI commands and UI to use the new formatting, and adds runtime IANA timezone validation and tests.

Changes

Cohort / File(s) Summary
Shared RRULE & Formatting
packages/shared/src/rrule.ts, packages/shared/src/rrule.test.ts
Added formatDateTimeInTimezone and FormatDateTimeInTimezoneOptions; changed RRULE serialization to emit floating DTSTART and convert TZDate to real Date via new Date(zoned.getTime()); tests added for timezone/DST behavior.
CLI: date formatting helper
packages/cli/src/commands/automations/format.ts
New exported formatAutomationDate(value, timezone) that normalizes inputs and delegates to formatDateTimeInTimezone, returning "—" for invalid/falsy values.
CLI: command outputs
packages/cli/src/commands/automations/create/command.ts, packages/cli/src/commands/automations/list/command.ts, packages/cli/src/commands/automations/resume/command.ts
Replaced raw ISO fallbacks with formatAutomationDate(..., timezone) when rendering nextRunAt in command messages and table columns.
CLI: update command payload
packages/cli/src/commands/automations/update/command.ts
Stop coercing missing device to null; now passes targetHostId as options.device, allowing undefined when omitted.
Desktop UI
apps/desktop/src/renderer/.../AutomationDetailSidebar/AutomationDetailSidebar.tsx
Replaced date-fns format usage with formatDateTimeInTimezone, passing the automation timezone for "Next run" and "Last ran" displays.
Schema validation
packages/trpc/src/router/automation/schema.ts
Enhanced timezone Zod schema to validate IANA timezone names at runtime using Intl.DateTimeFormat, rejecting invalid values with a clear message.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

I hopped through clocks and calendar folds, 🐰
Spun wall-times into local gold,
No more hardcoded ISO sighs,
DST dances now meet my eyes,
A rabbit’s whisker keeps the time bold.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix automation timezone scheduling' clearly and directly summarizes the main change: fixing timezone handling in automation scheduling across the codebase.
Description check ✅ Passed The description is comprehensive and well-structured, covering the core changes, verification steps, and migration requirements. All key sections are addressed with specific technical details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-automation-timezone

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This PR fixes automation recurrence scheduling by switching rrule.js to floating wall-clock DTSTART (no TZID), converting each occurrence to real UTC via rruleDateToUtc, and displaying run times in the automation's configured timezone across desktop and CLI surfaces. It also fixes the --device omission bug in automations update.

Confidence Score: 5/5

Safe to merge; the recurrence timezone math is correct and well-tested, and all remaining findings are P2 defensive-coding suggestions.

The floating-DTSTART approach is sound: wall-clock dates are stable across process timezones, each occurrence is correctly converted to real UTC via TZDate, and DST transitions are handled properly as confirmed by the new tests. The --device fix and IANA validation are correct. Both open comments are P2: the timezone-crash risk requires bad legacy DB data to trigger, and the HOURLY/DST note is a documentation suggestion. No P0/P1 defects found.

packages/shared/src/rrule.ts — worth adding a comment near buildRuleString about HOURLY DST fall-back ambiguity for future maintainers.

Important Files Changed

Filename Overview
packages/shared/src/rrule.ts Core fix: switches rrule.js to floating DTSTART (no TZID), converts each raw occurrence to real UTC via rruleDateToUtc, and adds formatDateTimeInTimezone. Logic is correct for DAILY/WEEKLY/MINUTELY; HOURLY across DST transitions has an inherent ambiguity worth documenting.
packages/trpc/src/router/automation/schema.ts Adds runtime IANA timezone validation via Intl.DateTimeFormat; clean, correct approach with no issues.
packages/cli/src/commands/automations/update/command.ts Fixes device-clearing bug: sends options.device (undefined when omitted) instead of options.device ?? null, so the server preserves existing targetHostId when --device is not passed.
packages/cli/src/commands/automations/format.ts New shared formatter that safely handles null/undefined date and timezone values, falling back to UTC and em-dash appropriately.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx Replaces date-fns format (UTC-local) with formatDateTimeInTimezone (automation timezone); correct behaviour change, but no error boundary for invalid legacy timezone values in the DB.
packages/shared/src/rrule.test.ts Adds well-targeted tests for the new UTC math and DST wall-clock stability; covers both PST→PDT transition and daily scheduling.
packages/cli/src/commands/automations/list/command.ts Uses formatAutomationDate for consistent timezone-aware display in the list table; straightforward and correct.
packages/cli/src/commands/automations/create/command.ts Switches next-run display from raw ISO string to timezone-aware formatAutomationDate; no issues.
packages/cli/src/commands/automations/resume/command.ts Replaces toISOString() with formatAutomationDate for the resume confirmation message; correct and consistent with other CLI commands.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Input: rrule body + dtstart (real UTC) + timezone"] --> B["formatRRuleLocalDtstart\n(dtstart → wall-clock in automation TZ)"]
    B --> C["buildRuleString\nDTSTART:{wall-clock} — no TZID\nRRULE:{rrule body}"]
    C --> D["RRule.fromString(ruleString)"]
    E["after (real UTC)"] --> F["utcToRruleDate(after, timezone)\n(real UTC → floating wall-clock)"]
    F --> G["rule.after(floatingAfter, false)"]
    D --> G
    G --> H{"next occurrence\n(floating wall-clock)"}
    H -->|null| I["throw: no future occurrences"]
    H -->|Date| J["rruleDateToUtc(next, timezone)\n(wall-clock UTC fields → real UTC via TZDate)"]
    J --> K["Return: plain Date in real UTC"]
    K --> L["formatDateTimeInTimezone(date, timezone)\nIntl.DateTimeFormat in automation TZ"]
    L --> M["Display: 'Apr 25, 2026 at 6:00 AM PDT'"]
Loading

Comments Outside Diff (1)

  1. packages/shared/src/rrule.ts, line 347-353 (link)

    P2 HOURLY rules have an inherent DST ambiguity worth documenting

    For FREQ=HOURLY with a floating DTSTART, rrule.js generates occurrences one rrule-hour apart in floating space. During a DST fall-back hour (e.g. 01:30 LA occurs twice), both instances share the same floating representation, so one real UTC instant is silently lost. During spring-forward, TZDate advances past the gap correctly but the cadence appears to skip an hour. This is an inherent trade-off of the floating-date approach; a short comment near this function would help future maintainers understand the expected behaviour.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/shared/src/rrule.ts
    Line: 347-353
    
    Comment:
    **`HOURLY` rules have an inherent DST ambiguity worth documenting**
    
    For `FREQ=HOURLY` with a floating DTSTART, rrule.js generates occurrences one rrule-hour apart in floating space. During a DST fall-back hour (e.g. `01:30` LA occurs twice), both instances share the same floating representation, so one real UTC instant is silently lost. During spring-forward, `TZDate` advances past the gap correctly but the cadence appears to skip an hour. This is an inherent trade-off of the floating-date approach; a short comment near this function would help future maintainers understand the expected behaviour.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx
Line: 84-88

Comment:
**Unguarded timezone string passed to `Intl.DateTimeFormat`**

`formatDateTimeInTimezone` calls `new Intl.DateTimeFormat(locale, { timeZone: timezone })` directly. If `automation.timezone` on a legacy row contains a value the runtime rejects (e.g. a renamed IANA zone or corrupted data), `Intl.DateTimeFormat` throws a `RangeError` that propagates unhandled through the JSX tree and crashes the sidebar. The new schema `.refine(isValidIanaTimezone)` prevents future bad writes, but existing rows are not retroactively validated. Adding a try-catch inside `formatDateTimeInTimezone` or a React error boundary around the sidebar would prevent a crash for edge-case legacy data.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/shared/src/rrule.ts
Line: 347-353

Comment:
**`HOURLY` rules have an inherent DST ambiguity worth documenting**

For `FREQ=HOURLY` with a floating DTSTART, rrule.js generates occurrences one rrule-hour apart in floating space. During a DST fall-back hour (e.g. `01:30` LA occurs twice), both instances share the same floating representation, so one real UTC instant is silently lost. During spring-forward, `TZDate` advances past the gap correctly but the cadence appears to skip an hour. This is an inherent trade-off of the floating-date approach; a short comment near this function would help future maintainers understand the expected behaviour.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Fix automation timezone scheduling" | Re-trigger Greptile

Comment on lines +84 to 88
? formatDateTimeInTimezone(
new Date(automation.nextRunAt),
automation.timezone,
)
: "—"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unguarded timezone string passed to Intl.DateTimeFormat

formatDateTimeInTimezone calls new Intl.DateTimeFormat(locale, { timeZone: timezone }) directly. If automation.timezone on a legacy row contains a value the runtime rejects (e.g. a renamed IANA zone or corrupted data), Intl.DateTimeFormat throws a RangeError that propagates unhandled through the JSX tree and crashes the sidebar. The new schema .refine(isValidIanaTimezone) prevents future bad writes, but existing rows are not retroactively validated. Adding a try-catch inside formatDateTimeInTimezone or a React error boundary around the sidebar would prevent a crash for edge-case legacy data.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx
Line: 84-88

Comment:
**Unguarded timezone string passed to `Intl.DateTimeFormat`**

`formatDateTimeInTimezone` calls `new Intl.DateTimeFormat(locale, { timeZone: timezone })` directly. If `automation.timezone` on a legacy row contains a value the runtime rejects (e.g. a renamed IANA zone or corrupted data), `Intl.DateTimeFormat` throws a `RangeError` that propagates unhandled through the JSX tree and crashes the sidebar. The new schema `.refine(isValidIanaTimezone)` prevents future bad writes, but existing rows are not retroactively validated. Adding a try-catch inside `formatDateTimeInTimezone` or a React error boundary around the sidebar would prevent a crash for edge-case legacy data.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 00ea424: formatDateTimeInTimezone now catches invalid timezone values and falls back to UTC formatting, so legacy/corrupt rows do not crash the sidebar.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/shared/src/rrule.test.ts (1)

296-296: Nit: prefer instanceof Date over constructor-name comparison.

expect(next.constructor.name).toBe("Date") is a brittle stand-in for an instanceof check — minified code or Date subclasses (notably TZDate, which is what this PR is specifically removing here) would also satisfy this string equality. The point of the assertion is to verify a plain Date, so use the more idiomatic check.

♻️ Proposed change
-		expect(next.constructor.name).toBe("Date");
+		expect(next).toBeInstanceOf(Date);
+		// Tighter check that this is not a TZDate subclass:
+		expect(Object.getPrototypeOf(next)).toBe(Date.prototype);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shared/src/rrule.test.ts` at line 296, Replace the brittle
constructor-name comparison in the test
(expect(next.constructor.name).toBe("Date")) with an instanceof/Jest matcher
check to assert a real Date object; update the assertion in
packages/shared/src/rrule.test.ts to use expect(next).toBeInstanceOf(Date) (or
expect(next instanceof Date).toBe(true)) so the test verifies a Date instance
robustly.
packages/trpc/src/router/automation/schema.ts (1)

17-30: Optional: improve timezone validation clarity.

The new Intl.DateTimeFormat(...) call relies on a side effect (throwing on invalid input). Consider one of these improvements for clarity:

  1. Explicit side-effect handling: Assign to a throwaway or wrap with void:

    function isValidIanaTimezone(timezone: string): boolean {
      try {
        void new Intl.DateTimeFormat(undefined, { timeZone: timezone });
        return true;
      } catch {
        return false;
      }
    }
  2. Stricter IANA-only validation (Node.js 20+): Use Intl.supportedValuesOf("timeZone") for direct lookups without exception handling:

    const IANA_ZONES = new Set(Intl.supportedValuesOf("timeZone"));
    function isValidIanaTimezone(timezone: string): boolean {
      return IANA_ZONES.has(timezone);
    }

Both approaches avoid exception-based control flow. Current behavior is correct, but these patterns are clearer and slightly more performant.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/trpc/src/router/automation/schema.ts` around lines 17 - 30, The
isValidIanaTimezone function relies on an exception side-effect — update it to
make the intent explicit by either (A) using a throwaway evaluation (e.g.,
prefix the constructor call with void) inside the try block so it’s clear you’re
only testing validity, or (B) if targeting Node 20+/browsers that support it,
build a Set from Intl.supportedValuesOf("timeZone") and replace
isValidIanaTimezone to check membership in that Set; apply the chosen change in
the isValidIanaTimezone function and keep the zod schema constant (the iana
constant) so the refine still uses the new validator.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/shared/src/rrule.ts`:
- Around line 423-438: Tests expecting the string built by
formatDateTimeInTimezone must be updated to match the actual Intl.DateTimeFormat
output (which includes comma separators for en-US) — replace expectations that
look for the " at " separator with the comma-separated form such as "Apr 25,
2026, 6:00 AM PDT" (and similar locale-specific variants used in the
assertions), leaving the formatDateTimeInTimezone function's explicit options
unchanged so the formatter remains stable.

---

Nitpick comments:
In `@packages/shared/src/rrule.test.ts`:
- Line 296: Replace the brittle constructor-name comparison in the test
(expect(next.constructor.name).toBe("Date")) with an instanceof/Jest matcher
check to assert a real Date object; update the assertion in
packages/shared/src/rrule.test.ts to use expect(next).toBeInstanceOf(Date) (or
expect(next instanceof Date).toBe(true)) so the test verifies a Date instance
robustly.

In `@packages/trpc/src/router/automation/schema.ts`:
- Around line 17-30: The isValidIanaTimezone function relies on an exception
side-effect — update it to make the intent explicit by either (A) using a
throwaway evaluation (e.g., prefix the constructor call with void) inside the
try block so it’s clear you’re only testing validity, or (B) if targeting Node
20+/browsers that support it, build a Set from
Intl.supportedValuesOf("timeZone") and replace isValidIanaTimezone to check
membership in that Set; apply the chosen change in the isValidIanaTimezone
function and keep the zod schema constant (the iana constant) so the refine
still uses the new validator.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6cde737a-98a4-4ba3-940a-38ed7fdfffcd

📥 Commits

Reviewing files that changed from the base of the PR and between 0fe65d2 and 88083e2.

📒 Files selected for processing (9)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx
  • packages/cli/src/commands/automations/create/command.ts
  • packages/cli/src/commands/automations/format.ts
  • packages/cli/src/commands/automations/list/command.ts
  • packages/cli/src/commands/automations/resume/command.ts
  • packages/cli/src/commands/automations/update/command.ts
  • packages/shared/src/rrule.test.ts
  • packages/shared/src/rrule.ts
  • packages/trpc/src/router/automation/schema.ts

Comment thread packages/shared/src/rrule.ts
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 25, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 9 files

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/shared/src/rrule.test.ts (2)

313-313: Prefer toBeInstanceOf(Date) over constructor.name.

expect(next.constructor.name).toBe("Date") is a string-based check that won't survive minification and is non-idiomatic for the test intent ("plain UTC Date instances"). toBeInstanceOf matches the matcher API used elsewhere and gives a better failure message.

-		expect(next.constructor.name).toBe("Date");
+		expect(next).toBeInstanceOf(Date);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shared/src/rrule.test.ts` at line 313, Replace the string-based
constructor name assertion with the instance matcher: in the test where you
currently use expect(next.constructor.name).toBe("Date"), change it to use
expect(next).toBeInstanceOf(Date) so the check is robust against minification
and matches the project's matcher style.

14-29: Helper assertions are too loose to catch wrong hour/day digits.

expectDateTimeParts checks each expected piece independently with toContain, which can yield false positives when one part's value is a substring of another. For example, hour: "6" is also a substring of year "2026", and day: "8" would be a substring of "2026" too — so a bug that produced the wrong hour/day could still pass these tests as long as the digit appears anywhere else in the formatted string (e.g., the year). It happens to work today only because the chosen years/days don't collide with the asserted hour/minute.

Consider asserting the structured time together (e.g., "6:00 AM") or using Intl.DateTimeFormat#formatToParts so each component is matched against its own slot rather than a substring of the whole string.

♻️ Sketch of a stricter helper
-function expectDateTimeParts(
-	formatted: string,
-	expected: {
-		month: string;
-		day: string;
-		year: string;
-		hour: string;
-		minute: string;
-		dayPeriod?: string;
-		timeZoneName: string;
-	},
-): void {
-	for (const value of Object.values(expected)) {
-		expect(formatted).toContain(value);
-	}
-}
+function expectDateTimeParts(
+	formatted: string,
+	expected: {
+		month: string;
+		day: string;
+		year: string;
+		hour: string;
+		minute: string;
+		dayPeriod?: string;
+		timeZoneName: string;
+	},
+): void {
+	// Assert the time slot as a unit so a wrong hour can't be masked by year digits.
+	const time = `${expected.hour}:${expected.minute}`;
+	expect(formatted).toContain(time);
+	expect(formatted).toContain(expected.month);
+	expect(formatted).toContain(expected.year);
+	expect(formatted).toContain(expected.timeZoneName);
+	if (expected.dayPeriod) expect(formatted).toContain(expected.dayPeriod);
+	// Day: match with a separator to avoid accidental substring hits.
+	expect(formatted).toMatch(new RegExp(`\\b${expected.day}\\b`));
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shared/src/rrule.test.ts` around lines 14 - 29, The helper
expectDateTimeParts is too loose because it checks each expected piece with
string containment, allowing false positives when parts (e.g., hour "6") appear
elsewhere (e.g., year "2026"); update expectDateTimeParts to assert components
in their own slots by using Intl.DateTimeFormat.prototype.formatToParts (or by
asserting a combined time substring like "6:00 AM") and compare each named part
(month, day, year, hour, minute, dayPeriod, timeZoneName) to the expected values
rather than using toContain on the full formatted string; locate and change the
implementation in expectDateTimeParts to parse formatToParts output and match
parts by their type (e.g.,
"hour","minute","day","month","year","dayPeriod","timeZoneName") or build and
assert a structured time token instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/shared/src/rrule.test.ts`:
- Line 313: Replace the string-based constructor name assertion with the
instance matcher: in the test where you currently use
expect(next.constructor.name).toBe("Date"), change it to use
expect(next).toBeInstanceOf(Date) so the check is robust against minification
and matches the project's matcher style.
- Around line 14-29: The helper expectDateTimeParts is too loose because it
checks each expected piece with string containment, allowing false positives
when parts (e.g., hour "6") appear elsewhere (e.g., year "2026"); update
expectDateTimeParts to assert components in their own slots by using
Intl.DateTimeFormat.prototype.formatToParts (or by asserting a combined time
substring like "6:00 AM") and compare each named part (month, day, year, hour,
minute, dayPeriod, timeZoneName) to the expected values rather than using
toContain on the full formatted string; locate and change the implementation in
expectDateTimeParts to parse formatToParts output and match parts by their type
(e.g., "hour","minute","day","month","year","dayPeriod","timeZoneName") or build
and assert a structured time token instead.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cb03ec17-9f85-4864-acf3-5ba8858f25d9

📥 Commits

Reviewing files that changed from the base of the PR and between 88083e2 and 00ea424.

📒 Files selected for processing (2)
  • packages/shared/src/rrule.test.ts
  • packages/shared/src/rrule.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/shared/src/rrule.ts

@saddlepaddle saddlepaddle merged commit 66c23d6 into main Apr 25, 2026
14 checks passed
MocA-Love pushed a commit to MocA-Love/superset that referenced this pull request Apr 26, 2026
* Fix automation timezone scheduling

* Stabilize automation timezone formatting tests
MocA-Love added a commit to MocA-Love/superset that referenced this pull request Apr 26, 2026
PR1〜PR5 (#435 #436 #437 #438 #440) で 13 commits 全件 cherry-pick + 手動 conflict 解消で取り込み済み。
本コミットは git 履歴上 behind=0 とするための ours マージ記録。

取り込み済み 13 commits:
- 1f55c62 Fix host service restart adoption (superset-sh#3732)
- 0fe65d2 test(desktop): remove host-service-coordinator test (superset-sh#3734)
- 3012b5a Add optimistic Electric collection updates (superset-sh#3722)
- c272a51 fix(desktop): drop branch row from v2 sidebar workspace item (superset-sh#3733)
- c2f3fdc feat(desktop): add fade-edge mask utilities (superset-sh#3735)
- 682d07c fix v2 terminal osc links (superset-sh#3736)
- 7c0d22b feat(ports): surface remote host-service ports in the sidebar (superset-sh#3676)
- 6a3be2d [codex] Stabilize v2 terminal resize (superset-sh#3739)
- 8928ac6 [codex] Improve v2 pane header responsiveness (superset-sh#3737)
- 5fe3d22 refactor(desktop): tidy v2 terminal session dropdown (superset-sh#3743)
- 66c23d6 Fix automation timezone scheduling (superset-sh#3738)
- 16e270c [codex] Add terminal session titles (superset-sh#3740)
- 583fa5d fix(desktop): refit v2 terminal after font settle (superset-sh#3742)
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