Skip to content

fix(api): preserve terminal scheduled automation dispatch - #6227

Open
abcdlsj wants to merge 8 commits into
ParadevAI:mainfrom
abcdlsj:fix/issue-6128-scheduled-dispatch
Open

abcdlsj wants to merge 8 commits into
ParadevAI:mainfrom
abcdlsj:fix/issue-6128-scheduled-dispatch

Conversation

@abcdlsj

@abcdlsj abcdlsj commented Aug 6, 2026 •

Copy link
Copy Markdown

Summary

Fixes #6128.

A bounded scheduled occurrence could be accepted by QStash and then dropped because evaluation disabled the automation before delivery. The dispatch route returned 200, so no retry, failure callback, or run record followed.

Design

  • Evaluate marks the queued payload as terminal when the recurrence has no next occurrence.
  • After enqueueing, evaluation moves that occurrence to an occurrence-specific future reservation in nextRunAt, using a CAS on enabled and the original nextRunAt. This keeps the terminal row out of the due scan while QStash delivers it, without a schema migration.
  • Dispatch accepts a terminal message while the reservation matches, and disables the automation only after dispatchAutomation records an outcome. A user pause is still rejected by the enabled guard; a changed reservation is stale.
  • The reservation is derived from the original occurrence, so a delayed message cannot claim a later terminal occurrence for the same automation.
  • Terminal finalization failures return non-2xx for QStash retry. If delivery retries are exhausted, run-failed records dispatch_failed and closes the matching recurrence. Existing dispatched or skipped_offline outcomes are preserved.
  • No database migration.

Checks

  • bun test apps/api/src/app/api/automations/evaluate/route.test.ts apps/api/src/app/api/automations/dispatch/[id]/route.test.ts apps/api/src/app/api/automations/run-failed/route.test.ts — 11 passed.
  • bunx biome check on changed files — passed.
  • bun run lint — passed.
  • API typecheck is blocked by the workspace missing next and next/server dependencies.

Summary by CodeRabbit

  • Bug Fixes

    • Improved automation scheduling to prevent stale or duplicate terminal dispatches.
    • Ensured terminal automations are finalized or disabled safely after successful or failed delivery.
    • Preserved correct recurrence timing for one-time and recurring automations.
    • Added safeguards against concurrent state changes and outdated scheduling information.
  • Tests

    • Expanded coverage for terminal, paused, disabled, recurring, and failed automation scenarios.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The evaluation route reserves terminal occurrences and queues dispatch metadata. The dispatch route validates and processes scheduled messages. The failure route records terminal delivery failures and conditionally disables matching automations. Tests cover terminal, recurring, stale, disabled, and failure paths.

Changes

Automation terminal lifecycle

Layer / File(s) Summary
Evaluate terminal occurrences
apps/api/src/app/api/automations/evaluate/route.ts, apps/api/src/app/api/automations/evaluate/route.test.ts
The evaluator computes each occurrence once, queues terminal metadata and reservation timestamps, and conditionally advances terminal or recurring schedules.
Dispatch terminal messages
apps/api/src/app/api/automations/dispatch/[id]/route.ts, apps/api/src/app/api/automations/dispatch/[id]/route.test.ts
The dispatch route validates terminal reservations and UTC-minute occurrence matches, dispatches valid messages, and conditionally finalizes terminal automations. Tests cover disabled, stale, error, terminal, and non-terminal paths.
Record terminal failures
apps/api/src/app/api/automations/run-failed/route.ts, apps/api/src/app/api/automations/run-failed/route.test.ts
The failure route records dispatch_failed runs only for runs in dispatching status and conditionally disables matching enabled automations.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AutomationEvaluationRoute
  participant QStash
  participant DispatchRoute
  participant RunFailedRoute
  participant Database
  participant AutomationDispatch
  AutomationEvaluationRoute->>Database: read due automation
  AutomationEvaluationRoute->>AutomationEvaluationRoute: compute and reserve occurrence
  AutomationEvaluationRoute->>QStash: enqueue terminal or recurring payload
  QStash->>DispatchRoute: deliver scheduled payload
  DispatchRoute->>Database: validate automation state
  DispatchRoute->>AutomationDispatch: dispatch valid occurrence
  DispatchRoute->>Database: finalize terminal automation
  QStash->>RunFailedRoute: deliver terminal failure
  RunFailedRoute->>Database: record dispatch_failed run
  RunFailedRoute->>Database: disable matching terminal automation
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Linked Issues check ✅ Passed The changes address issue #6128 by preserving terminal dispatches and recording observable outcomes for dispatch success or failure.
Out of Scope Changes check ✅ Passed The code and tests are directly related to terminal automation dispatch, failure handling, recurrence closure, and the linked issue.
Description check ✅ Passed The description explains the issue, design, testing, and known typecheck limitation; it provides the required information despite different section headings.
Title check ✅ Passed The title uses conventional commit format and clearly describes the fix for terminal scheduled automation dispatches.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR preserves delivery of a bounded automation’s final scheduled occurrence after evaluation disables the exhausted recurrence.

  • Adds a signed terminal marker to QStash payloads.
  • Lets matching terminal messages bypass the normal disabled-automation guard.
  • Adds stale-schedule validation and focused evaluate/dispatch tests.

Confidence Score: 3/5

This PR should not merge until terminal delivery can distinguish evaluator exhaustion from a user pause made after enqueue.

The new terminal bypass allows a signed queued message to start an agent after the user has disabled the automation because both disable paths preserve the same nextRunAt value.

Files Needing Attention: apps/api/src/app/api/automations/dispatch/[id]/route.ts

Security Review

A terminal message can still execute after a user pauses the automation between enqueue and delivery because user pause and recurrence exhaustion produce the same persisted enabled and nextRunAt state.

Important Files Changed

Filename Overview
apps/api/src/app/api/automations/dispatch/[id]/route.ts Adds terminal-message handling and stale-minute validation, but permits a queued terminal run after a user pause.
apps/api/src/app/api/automations/evaluate/route.ts Computes recurrence advancement once, marks exhausted occurrences terminal, and disables them after enqueue.
apps/api/src/app/api/automations/dispatch/[id]/route.test.ts Covers exhausted-terminal, disabled non-terminal, and enabled dispatch paths, but not a user pause occurring after terminal enqueue.
apps/api/src/app/api/automations/evaluate/route.test.ts Verifies terminal marking and preserves the existing non-terminal advancement behavior.
Prompt To Fix All With AI
### Issue 1
apps/api/src/app/api/automations/dispatch/[id]/route.ts:63-64
**Terminal dispatch bypasses user pause**

When a user pauses an automation after its terminal occurrence is enqueued but before delivery, `terminal` bypasses the disabled guard and the unchanged `nextRunAt` passes the stale check, causing `dispatchAutomation` to create a run and potentially start an agent despite the pause.

**How this was verified:** The pause path preserves `nextRunAt`, while this route accepts a matching terminal message and the dispatcher performs side effects without another enabled-state check.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(api): preserve terminal scheduled au..." | Re-trigger Greptile

Comment on lines +63 to +64
const scheduledFor = new Date(parsed.data.scheduledFor);
if (!automation.enabled && !parsed.data.terminal) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 security Terminal dispatch bypasses user pause

When a user pauses an automation after its terminal occurrence is enqueued but before delivery, terminal bypasses the disabled guard and the unchanged nextRunAt passes the stale check, causing dispatchAutomation to create a run and potentially start an agent despite the pause.

How this was verified: The pause path preserves nextRunAt, while this route accepts a matching terminal message and the dispatcher performs side effects without another enabled-state check.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/api/src/app/api/automations/dispatch/[id]/route.ts
Line: 63-64

Comment:
**Terminal dispatch bypasses user pause**

When a user pauses an automation after its terminal occurrence is enqueued but before delivery, `terminal` bypasses the disabled guard and the unchanged `nextRunAt` passes the stale check, causing `dispatchAutomation` to create a run and potentially start an agent despite the pause.

**How this was verified:** The pause path preserves `nextRunAt`, while this route accepts a matching terminal message and the dispatcher performs side effects without another enabled-state check.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/app/api/automations/dispatch/`[id]/route.test.ts:
- Around line 80-133: Add a test alongside the terminal-dispatch cases that
submits a terminal payload whose scheduledFor minute differs from
automation.nextRunAt. Assert the POST response is successful with skipped:
"stale", and verify dispatchAutomation was not called.
🪄 Autofix

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 Plus

Run ID: dc66d563-c347-42e8-8479-9cf524e3a6ed

📥 Commits

Reviewing files that changed from the base of the PR and between c920d52 and 4bded79.

📒 Files selected for processing (4)
  • apps/api/src/app/api/automations/dispatch/[id]/route.test.ts
  • apps/api/src/app/api/automations/dispatch/[id]/route.ts
  • apps/api/src/app/api/automations/evaluate/route.test.ts
  • apps/api/src/app/api/automations/evaluate/route.ts

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 4 files

Architecture diagram
sequenceDiagram
    participant Sched as Cron / Scheduler
    participant Eval as Evaluate Route
    participant DB as Database
    participant QStash as QStash Queue
    participant Dispatch as Dispatch Route
    participant Dispatcher as Automation Dispatcher

    note over Sched,Dispatcher: Scheduled Automation Dispatch with Terminal Handling

    Sched->>Eval: POST /api/automations/evaluate (cron trigger)

    Eval->>DB: Select due automations (enabled, nextRunAt <= now)
    DB-->>Eval: List of due automations

    loop For each due automation
        Eval->>Eval: Compute next occurrence after current nextRunAt
        alt Has next occurrence (non-terminal)
            Eval-->>Eval: next = computedDate
        else No next occurrence (terminal)
            Eval-->>Eval: next = null
        end

        Eval->>QStash: batchJSON - enqueue dispatch message
        note over Eval,QStash: body includes { terminal: (next === null) }

        alt next is null (terminal)
            Eval->>DB: UPDATE set { enabled: false }
        else next exists (non-terminal)
            Eval->>DB: UPDATE set { nextRunAt: next }
        end
    end

    QStash-->>Dispatch: Deliver queued message (after delay)

    Dispatch->>Dispatch: Verify QStash signature (signed payload)
    Dispatch->>DB: SELECT automation by id
    DB-->>Dispatch: Automation record

    alt Automation not found
        Dispatch-->>QStash: 200 { skipped: "deleted" }
    else Automation disabled AND NOT terminal
        Dispatch-->>QStash: 200 { skipped: "disabled" }
    else Terminal AND scheduledFor minute != automation.nextRunAt minute
        note over Dispatch: Schedule changed after enqueue
        Dispatch-->>QStash: 200 { skipped: "stale" }
    else Automation enabled OR (disabled + terminal + matching minute)
        Dispatch->>Dispatcher: dispatchAutomation({ automation, scheduledFor })
        alt Dispatcher succeeds
            Dispatcher-->>Dispatch: { status: "dispatched", runId }
            Dispatch-->>QStash: 200 { ok: true, outcome }
        else Dispatcher fails (offline/failed)
            Dispatcher-->>Dispatch: { status: "offline" | "dispatch_failed" }
            Dispatch-->>QStash: 200 { ok: true, outcome }
        end
    end
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

@abcdlsj

abcdlsj commented Aug 6, 2026

Copy link
Copy Markdown
Author

Addressed in f272fcf.

The Greptile finding was valid. A terminal occurrence now remains enabled while it is queued, so a user pause before delivery is honored. The dispatch route or QStash failure callback closes the recurrence only after an observable outcome, using a conditional occurrence match. Added coverage for user pause, stale terminal delivery, and terminal delivery failure.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/app/api/automations/dispatch/`[id]/route.ts:
- Around line 80-91: The terminal dispatch error path around
finalizeTerminalAutomation must not acknowledge the message with HTTP 200 after
finalization fails. Persist a durable, idempotent finalization retry before
returning, using the existing retry mechanism or a dedicated persisted job
rather than normal terminal evaluation, while preserving the successful dispatch
outcome and avoiding duplicate terminal processing.
🪄 Autofix

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 Plus

Run ID: 6096adf9-f4cf-4711-b6e0-d56b95b58616

📥 Commits

Reviewing files that changed from the base of the PR and between 4bded79 and f272fcf.

📒 Files selected for processing (6)
  • apps/api/src/app/api/automations/dispatch/[id]/route.test.ts
  • apps/api/src/app/api/automations/dispatch/[id]/route.ts
  • apps/api/src/app/api/automations/evaluate/route.test.ts
  • apps/api/src/app/api/automations/evaluate/route.ts
  • apps/api/src/app/api/automations/run-failed/route.test.ts
  • apps/api/src/app/api/automations/run-failed/route.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/src/app/api/automations/evaluate/route.ts

@abcdlsj

abcdlsj commented Aug 6, 2026

Copy link
Copy Markdown
Author

Addressed the finalization retry finding in c22b4ad.

If terminal finalization fails after dispatch has recorded an outcome, the route now returns non-2xx so QStash retries the idempotent finalization. If retries exhaust, run-failed preserves an existing completed/offline run instead of rewriting it as dispatch_failed, then closes the recurrence.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api/src/app/api/automations/dispatch/[id]/route.ts (1)

63-78: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Claim terminal delivery before invoking the dispatcher.

The test at apps/api/src/app/api/automations/dispatch/[id]/route.test.ts:158 already expects that disabling the automation before dispatchAutomation prevents terminal delivery. The current route uses the preloaded automation.enabled value, so a user pause between lines 63 and 74 allows delivery of a terminal occurrence. Use a guarded, durable claim on the automation state before dispatch and only dispatch when that update succeeds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/app/api/automations/dispatch/`[id]/route.ts around lines 63 -
78, Update the route’s terminal-dispatch flow around the enabled and stale
checks to atomically claim the terminal occurrence in durable automation state
before calling dispatchAutomation. Re-read or condition the update on the
automation still being enabled and matching the scheduled run, and invoke
dispatchAutomation only when the guarded claim succeeds; otherwise return the
appropriate skipped response and prevent delivery after a concurrent pause.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/api/src/app/api/automations/dispatch/`[id]/route.ts:
- Around line 63-78: Update the route’s terminal-dispatch flow around the
enabled and stale checks to atomically claim the terminal occurrence in durable
automation state before calling dispatchAutomation. Re-read or condition the
update on the automation still being enabled and matching the scheduled run, and
invoke dispatchAutomation only when the guarded claim succeeds; otherwise return
the appropriate skipped response and prevent delivery after a concurrent pause.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a655a98c-78c2-42bc-8d10-864d8c56b20a

📥 Commits

Reviewing files that changed from the base of the PR and between f272fcf and c22b4ad.

📒 Files selected for processing (4)
  • apps/api/src/app/api/automations/dispatch/[id]/route.test.ts
  • apps/api/src/app/api/automations/dispatch/[id]/route.ts
  • apps/api/src/app/api/automations/run-failed/route.test.ts
  • apps/api/src/app/api/automations/run-failed/route.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/api/src/app/api/automations/run-failed/route.test.ts
  • apps/api/src/app/api/automations/run-failed/route.ts

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api/src/app/api/automations/dispatch/[id]/route.ts (1)

63-82: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Claim terminal delivery before dispatchAutomation.

If a user pause commits after Line 64 reads automation.enabled but before Line 78 calls dispatchAutomation, this route still dispatches the terminal occurrence. finalizeTerminalAutomation only guards the post-dispatch update.

Create a durable conditional delivery claim before dispatch. Match the automation ID, enabled state, and terminal reservation. Make the pause flow coordinate with that claim.

As per PR objectives, terminal delivery must preserve user pauses.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/app/api/automations/dispatch/`[id]/route.ts around lines 63 -
82, Before calling dispatchAutomation in the route handler, atomically claim the
terminal delivery using the automation ID, enabled state, and terminal
reservation, and return the existing skipped response when the claim fails.
Update the pause flow to coordinate with this claim so a pause committed
concurrently prevents terminal dispatch; retain finalizeTerminalAutomation for
post-dispatch finalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/api/src/app/api/automations/dispatch/`[id]/route.ts:
- Around line 63-82: Before calling dispatchAutomation in the route handler,
atomically claim the terminal delivery using the automation ID, enabled state,
and terminal reservation, and return the existing skipped response when the
claim fails. Update the pause flow to coordinate with this claim so a pause
committed concurrently prevents terminal dispatch; retain
finalizeTerminalAutomation for post-dispatch finalization.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bed4ab79-2f7c-4330-a640-6220fc4a8ff9

📥 Commits

Reviewing files that changed from the base of the PR and between 596968e and 8c8041f.

📒 Files selected for processing (6)
  • apps/api/src/app/api/automations/dispatch/[id]/route.test.ts
  • apps/api/src/app/api/automations/dispatch/[id]/route.ts
  • apps/api/src/app/api/automations/evaluate/route.test.ts
  • apps/api/src/app/api/automations/evaluate/route.ts
  • apps/api/src/app/api/automations/run-failed/route.test.ts
  • apps/api/src/app/api/automations/run-failed/route.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/api/src/app/api/automations/run-failed/route.test.ts
  • apps/api/src/app/api/automations/evaluate/route.ts

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

@abcdlsj

abcdlsj commented Aug 7, 2026

Copy link
Copy Markdown
Author

Addressed the latest review findings in 93383c0.

  • Replaced the 100-year nextRunAt sentinel with an updatedAt-based terminal reservation token, preserving the real scheduled occurrence.
  • Added a conditional terminal claim immediately before dispatch so a concurrent user pause or schedule change prevents delivery.
  • Terminal dispatch conflicts now return 409 so QStash can retry/fail the message instead of acknowledging an unresolved run.
  • Shared terminal occurrence matching between dispatch and run-failed, with tests asserting the actual CAS predicates and stale/user-paused no-op paths.

Checks: focused automation tests 14/14; Biome and repository lint pass. API typecheck remains blocked by the workspace missing next/next-server type dependencies.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 7 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

@abcdlsj

abcdlsj commented Aug 10, 2026

Copy link
Copy Markdown
Author

Addressed the latest Cubic findings in d9f1d96:

  • Dispatch retries the terminal claim against the exact evaluator reservation if evaluation wins between SELECT and CAS.
  • Terminal reservation CAS values use a UTC ISO token with microsecond precision; evaluate, dispatch, and run-failed avoid millisecond-only Date equality.
  • Centralized minute bucketing and added coverage for the evaluator race, reserved-but-stale occurrence, and enabled-guard isolation.

Validation: automation route tests 16/16, shared RRULE tests 48/48, shared/trpc typecheck, Biome, and repository lint pass. API typecheck remains blocked by missing workspace Next.js type dependencies.

@abcdlsj
abcdlsj force-pushed the fix/issue-6128-scheduled-dispatch branch from 1d90272 to 12556ec Compare August 25, 2026 06:36

This branch has not been deployed

No deployments
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.

Scheduled automation dispatch silently lost while target host is verifiably online; manual 'automations run' succeeds minutes later

1 participant