Skip to content

fix(onboarding): /setup/tasks must not re-create an existing schedule (chat#1889 row 12)#1898

Open
sweetmantech wants to merge 1 commit into
mainfrom
feat/setup-tasks-no-recreate
Open

fix(onboarding): /setup/tasks must not re-create an existing schedule (chat#1889 row 12)#1898
sweetmantech wants to merge 1 commit into
mainfrom
feat/setup-tasks-no-recreate

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Matrix row 12 in chat#1889. Independent of the other row-12 PRs (#1896, #1897).

Why

FirstTaskStep pre-ran a fresh weekly report and then scheduled it — on every visit, unconditionally. So a user who returned to /setup/tasks, or simply re-clicked the welcome email's step 4 link, got:

  • a duplicate billed LLM run (the pre-run is a real agent turn), and
  • a second schedule on the account

This is the same duplicate-schedule class of bug the task-email audit has hit before, reached through onboarding this time.

What changed

  • findExistingWeeklyReportTask — returns the account's enabled task. A paused schedule deliberately does not count, so a user who disabled theirs can still set one up.
  • ExistingWeeklyReportPanel — surfaces the existing schedule with its next run and most recent run, linking to /tasks, instead of running anything.
  • FirstTaskStep waits for the tasks read before deciding, so the pre-run cannot fire while useScheduledActions is still loading — otherwise the race would re-introduce the duplicate on a slow read.

Verification

TDD, red → green:

```

RED — module not found

Test Files 1 failed (1)
Tests no tests

GREEN

pnpm exec vitest run lib/onboarding components/Onboarding
Test Files 18 passed (18)
Tests 72 passed (72)
```

Unit tests cover: enabled task returned, disabled ignored, empty/undefined → null (first-run still pre-runs), and first-enabled-wins with a mixed list.

pnpm exec tsc --noEmit clean for the touched files. Preview click-through pending (needs an authed account with an existing enabled task).

Tracked in chat#1889 (matrix row 12).


Summary by cubic

Fixes onboarding so /setup/tasks no longer re-runs and re-schedules the weekly report when one already exists. Prevents duplicate billed LLM runs and multiple schedules (chat#1889, row 12).

  • Bug Fixes
    • Detect an existing enabled weekly report and skip pre-run; paused schedules don’t count.
    • Show an existing-schedule panel with next/last run info and a link to /tasks.
    • Wait for tasks to load before deciding, preventing race conditions that could trigger a duplicate run.

Written for commit 2f0a282. Summary will update on new commits.

Review in cubic

chat#1889 matrix row 12.

FirstTaskStep pre-ran a fresh weekly report and scheduled it on every visit. A
return visit, or a re-click of the welcome email's step 4 link, therefore billed
a duplicate LLM run and left the account with a second schedule.

- New findExistingWeeklyReportTask picks the account's enabled task; a paused
  schedule does not count, so the step still offers to set one up.
- New ExistingWeeklyReportPanel surfaces the existing schedule with its next and
  most recent run instead.
- FirstTaskStep waits for the tasks read before deciding, so the pre-run can't
  fire while tasks are still loading.

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

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview Jul 27, 2026 5:05am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@sweetmantech, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 552acd32-487b-4519-b71f-6e7d4b1e5b1e

📥 Commits

Reviewing files that changed from the base of the PR and between a2d8cf8 and 2f0a282.

⛔ Files ignored due to path filters (1)
  • lib/onboarding/__tests__/findExistingWeeklyReportTask.test.ts is excluded by !**/*.test.* and included by lib/**
📒 Files selected for processing (3)
  • components/Onboarding/ExistingWeeklyReportPanel.tsx
  • components/Onboarding/FirstTaskStep.tsx
  • lib/onboarding/findExistingWeeklyReportTask.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/setup-tasks-no-recreate

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f0a282062

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

// run and left a second schedule behind. Wait for the read before deciding, so
// the pre-run isn't kicked off while tasks are still loading.
const existingTask = findExistingWeeklyReportTask(tasksQuery.data);
if (tasksQuery.isLoading) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Wait for a successful task refresh before starting the report

isLoading only covers the initial fetch: it is false while React Query background-refetches cached data and after a request ultimately errors. If the cache contains an old empty list, or /api/tasks fails while other endpoints still work, existingTask remains null and FirstTaskReportRun immediately sends the billed prompt before the current schedule state is known; a returning user can therefore still incur the duplicate run and, after confirming, create another schedule. Proceed only after a successful, settled task read and show an error/retry state otherwise.

Useful? React with 👍 / 👎.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 4 files

Confidence score: 2/5

  • In components/Onboarding/FirstTaskStep.tsx, the pre-run can start FirstTaskReportRun while task data is still stale/empty or after a failed read, so users may trigger onboarding report creation before the no-schedule guard is actually validated; gate this path on a completed successful tasks fetch before launching the run.
  • In components/Onboarding/ExistingWeeklyReportPanel.tsx, the existing-task check appears too broad, so any unrelated enabled scheduled task can be misclassified as the onboarding weekly report and block step completion; scope the lookup to the onboarding weekly-report task type (and relevant metadata) to avoid false positives.
  • components/Onboarding/FirstTaskStep.tsx has grown past the readability/single-responsibility size guideline, which raises regression risk around guard ordering and async edge cases in this flow; split the new early-return/guard logic into focused helpers or subcomponents to make behavior easier to verify and maintain.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="components/Onboarding/ExistingWeeklyReportPanel.tsx">

<violation number="1" location="components/Onboarding/ExistingWeeklyReportPanel.tsx:24">
P1: Accounts with an unrelated enabled scheduled task are told their weekly report already exists and cannot complete this onboarding step. Filter the existing-task lookup to the onboarding weekly-report task (and ideally the selected artist) before rendering this panel.</violation>
</file>

<file name="components/Onboarding/FirstTaskStep.tsx">

<violation number="1" location="components/Onboarding/FirstTaskStep.tsx:43">
P1: Returning with a cached empty task list while its refetch is in flight, or after the tasks read fails, still starts `FirstTaskReportRun` before this guard verifies no schedule exists. Gate the pre-run on a completed successful read (and active fetches) so these paths cannot bill and schedule a duplicate.</violation>

<violation number="2" location="components/Onboarding/FirstTaskStep.tsx:43">
P2: Custom agent: **Code Structure and Size Limits for Readability and Single Responsibility**

This file now totals 117 lines, exceeding the 100-line limit for readability and single-responsibility. The newly added early-return blocks for `tasksQuery.isLoading` and `existingTask` pushed the component over the threshold. Consider extracting these into smaller sub-components (e.g., `FirstTaskLoadingState` and `ExistingWeeklyReportPanel` already exists) or moving the conditional orchestration into a wrapper hook to keep this file under 100 lines.</violation>
</file>

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

Re-trigger cubic

<CalendarClock className="size-10 text-muted-foreground" />
<div>
<h1 className="text-2xl font-semibold text-foreground">
Your weekly report is already set up

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Accounts with an unrelated enabled scheduled task are told their weekly report already exists and cannot complete this onboarding step. Filter the existing-task lookup to the onboarding weekly-report task (and ideally the selected artist) before rendering this panel.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At components/Onboarding/ExistingWeeklyReportPanel.tsx, line 24:

<comment>Accounts with an unrelated enabled scheduled task are told their weekly report already exists and cannot complete this onboarding step. Filter the existing-task lookup to the onboarding weekly-report task (and ideally the selected artist) before rendering this panel.</comment>

<file context>
@@ -0,0 +1,45 @@
+      <CalendarClock className="size-10 text-muted-foreground" />
+      <div>
+        <h1 className="text-2xl font-semibold text-foreground">
+          Your weekly report is already set up
+        </h1>
+        <p className="mt-1 text-sm text-muted-foreground">
</file context>

// run and left a second schedule behind. Wait for the read before deciding, so
// the pre-run isn't kicked off while tasks are still loading.
const existingTask = findExistingWeeklyReportTask(tasksQuery.data);
if (tasksQuery.isLoading) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Returning with a cached empty task list while its refetch is in flight, or after the tasks read fails, still starts FirstTaskReportRun before this guard verifies no schedule exists. Gate the pre-run on a completed successful read (and active fetches) so these paths cannot bill and schedule a duplicate.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At components/Onboarding/FirstTaskStep.tsx, line 43:

<comment>Returning with a cached empty task list while its refetch is in flight, or after the tasks read fails, still starts `FirstTaskReportRun` before this guard verifies no schedule exists. Gate the pre-run on a completed successful read (and active fetches) so these paths cannot bill and schedule a duplicate.</comment>

<file context>
@@ -31,6 +35,28 @@ const FirstTaskStep = () => {
+  // run and left a second schedule behind. Wait for the read before deciding, so
+  // the pre-run isn't kicked off while tasks are still loading.
+  const existingTask = findExistingWeeklyReportTask(tasksQuery.data);
+  if (tasksQuery.isLoading) {
+    return (
+      <div className="mx-auto flex w-full max-w-3xl flex-col gap-4 px-4 py-8">
</file context>
Suggested change
if (tasksQuery.isLoading) {
if (tasksQuery.isFetching || !tasksQuery.isSuccess) {

// run and left a second schedule behind. Wait for the read before deciding, so
// the pre-run isn't kicked off while tasks are still loading.
const existingTask = findExistingWeeklyReportTask(tasksQuery.data);
if (tasksQuery.isLoading) {

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: Custom agent: Code Structure and Size Limits for Readability and Single Responsibility

This file now totals 117 lines, exceeding the 100-line limit for readability and single-responsibility. The newly added early-return blocks for tasksQuery.isLoading and existingTask pushed the component over the threshold. Consider extracting these into smaller sub-components (e.g., FirstTaskLoadingState and ExistingWeeklyReportPanel already exists) or moving the conditional orchestration into a wrapper hook to keep this file under 100 lines.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At components/Onboarding/FirstTaskStep.tsx, line 43:

<comment>This file now totals 117 lines, exceeding the 100-line limit for readability and single-responsibility. The newly added early-return blocks for `tasksQuery.isLoading` and `existingTask` pushed the component over the threshold. Consider extracting these into smaller sub-components (e.g., `FirstTaskLoadingState` and `ExistingWeeklyReportPanel` already exists) or moving the conditional orchestration into a wrapper hook to keep this file under 100 lines.</comment>

<file context>
@@ -31,6 +35,28 @@ const FirstTaskStep = () => {
+  // run and left a second schedule behind. Wait for the read before deciding, so
+  // the pre-run isn't kicked off while tasks are still loading.
+  const existingTask = findExistingWeeklyReportTask(tasksQuery.data);
+  if (tasksQuery.isLoading) {
+    return (
+      <div className="mx-auto flex w-full max-w-3xl flex-col gap-4 px-4 py-8">
</file context>

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