-
-
Notifications
You must be signed in to change notification settings - Fork 19
Add scheduling algorithm #3062
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add scheduling algorithm #3062
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. |
Warning Rate limit exceeded@vhpx has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 22 minutes and 44 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
WalkthroughA new scheduling module was introduced, defining interfaces and constants for managing tasks, events, and active hours using dayjs for date handling. Corresponding tests were added to verify these interfaces and constants. The dayjs dependency was added to the package manifest. No changes were made to existing exported entities. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Scheduler
participant dayjs
User->>Scheduler: Provide tasks and active hours
Scheduler->>dayjs: Round and calculate time slots
Scheduler->>Scheduler: Schedule tasks respecting deadlines and constraints
Scheduler-->>User: Return scheduled events and logs
Suggested labels
Poem
✨ Finishing Touches
🧪 Generate 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/ai/src/scheduling/algorithm.ts (1)
57-57
: Consider implementing the schedule function or removing the placeholder.The commented-out
schedule
function suggests incomplete implementation. Either implement the function or remove the placeholder to avoid confusion.Would you like me to help implement a basic scheduling algorithm or should this placeholder be removed for now?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lock
is excluded by!**/*.lock
📒 Files selected for processing (3)
packages/ai/package.json
(1 hunks)packages/ai/src/scheduling/algorithm.test.ts
(1 hunks)packages/ai/src/scheduling/algorithm.ts
(1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeFactor
packages/ai/src/scheduling/algorithm.test.ts
[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Deploy-Preview
- GitHub Check: Deploy-Preview
- GitHub Check: Deploy-Preview
🔇 Additional comments (3)
packages/ai/package.json (1)
46-46
:✅ Verification successful
Verify the dayjs version for security and currency.
The dayjs version
^1.11.13
should be verified to ensure it's current and free from known vulnerabilities.
🌐 Web query:
What is the latest version of dayjs and are there any known security vulnerabilities in version 1.11.13?
💡 Result:
As of June 9, 2025, the latest stable version of Day.js is 1.11.13, released approximately seven months ago. (npmjs.com)
Regarding security vulnerabilities, there are no direct vulnerabilities reported for Day.js version 1.11.13 in Snyk's vulnerability database. (security.snyk.io) However, it's important to note that Day.js version 1.11.10 depends on Moment.js, which has a known security vulnerability (CVE-2022-31129). (github.com) Since version 1.11.13 is the latest release, it is likely that this dependency has been updated or addressed.
For the most current information on security vulnerabilities and updates, it's recommended to consult the official Day.js GitHub repository or the Snyk vulnerability database.
Citations:
- 1: https://www.npmjs.com/package/dayjs?utm_source=openai
- 2: https://security.snyk.io/package/npm/dayjs/1.11.13?utm_source=openai
- 3: Day.js v1.11.10 depends on Moment.js which has a known security vulnerability (CVE-2022-31129) iamkun/dayjs#2530
Confirm Day.js version is current and secure
The
dayjs
dependency at^1.11.13
is the latest stable release (as of June 2025) and has no reported vulnerabilities. No further changes needed.packages/ai/src/scheduling/algorithm.test.ts (2)
1-184
: Excellent test coverage and structure.The test suite is comprehensive and well-organized, covering all interfaces and default constants with appropriate assertions. The structure follows good testing practices with clear describe blocks and focused test cases.
🧰 Tools
🪛 GitHub Check: CodeFactor
[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)
176-183
: TODO comments are intentional for future implementation.The TODO comments in the test file are placeholders for the
schedule
function implementation, which is currently commented out in the algorithm file. These are intentional and provide a clear roadmap for future development.🧰 Tools
🪛 GitHub Check: CodeFactor
[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)
a0490ba
to
78e9cd2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
♻️ Duplicate comments (1)
apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx (1)
45-56
: Same colour helper repeated across three componentsExtract to
@tuturuuu/ui/theme
(or similar) to ensure consistent updates.
🧹 Nitpick comments (9)
apps/calendar/src/app/[locale]/layout.tsx (1)
115-117
: Background token diverges from childrenThe root layout now uses
bg-root-background
whereas the navbar keepsbg-background
. Make sure both tokens exist in the Tailwind theme and intentionally differ; otherwise you might get an unexpected color seam between the header and body.apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx (2)
30-46
: Hash function can be simplified & made deterministic
a & a
is a no-op; it just returnsa
. To clamp to 32-bit you likely wanteda & 0xffffffff
. Consider cleaning this up for readability.- return a & a; + return a & 0xffffffff;
179-182
: Sorting mutatesdailyEvents
, risking unexpected re-renders
dailyEvents.sort(...)
mutates the original array held ingroupedEvents
, which is memoised. On subsequent renders this may violate React’s expectations and break referential equality checks.-const sortedEvents = dailyEvents.sort((a, b) => - a.range.start.diff(b.range.start) -); +const sortedEvents = [...dailyEvents].sort((a, b) => + a.range.start.diff(b.range.start) +);apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx (1)
146-148
:onOpenChange
handler ignores the boolean parameter
<Dialog open={isOpen} onOpenChange={handleClose}>
passesnewOpen: boolean
tohandleClose
, but the function signature() => void
discards it.
If the modal were ever opened by the dialog itself (e.g. via keyboard shortcut), the handler would immediately invokeonClose()
and reset the form.
Accept the parameter and early-return whennewOpen
istrue
.apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx (1)
119-130
: DRY: consolidate colour helpers
getCategoryColor
duplicates identical logic found in other components.
Export once from a sharedutils/colors.ts
to avoid drift.apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx (1)
34-44
: Icon detection is brittle & case-sensitive
name.includes('Split')
misses “Task Splitting Challenge”.
Compare lower-cased strings or use regexes on keyword arrays.packages/ai/src/scheduling/algorithm.ts (1)
244-290
:getNextAvailableTime
ignores later rangesOnly the first range of
hours
is inspected (const firstHour = hours[0]
).
For multiple daily ranges (e.g., lunch break gap), early slots may be missed. Iterate all ranges whenday === 0
.apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx (2)
82-100
: Inefficient per-tasksort
inside a loop.
events.filter(...).sort(...)
is executed for every task, producing O(T × E log E) complexity and repeated array copies.
A quicker alternative:
- Build a
Map<taskId, Event[]>
once.- Keep only the last event per task while populating the map.
This removes the nested filter/sort and scales linearly with
events.length
.
129-130
: Unresolved TODO leaveslargestGap
always zero.Either compute the metric or omit it from the UI until implemented to avoid misleading analytics.
I can help sketch the gap-calculation if useful.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lock
is excluded by!**/*.lock
📒 Files selected for processing (16)
apps/calendar/src/app/[locale]/(root)/navbar.tsx
(1 hunks)apps/calendar/src/app/[locale]/(root)/page.tsx
(2 hunks)apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx
(1 hunks)apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx
(1 hunks)apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
(1 hunks)apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx
(1 hunks)apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx
(1 hunks)apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx
(1 hunks)apps/calendar/src/app/[locale]/layout.tsx
(1 hunks)packages/ai/package.json
(1 hunks)packages/ai/src/scheduling/algorithm.test.ts
(1 hunks)packages/ai/src/scheduling/algorithm.ts
(1 hunks)packages/ai/src/scheduling/default.ts
(1 hunks)packages/ai/src/scheduling/templates.ts
(1 hunks)packages/ai/src/scheduling/types.ts
(1 hunks)packages/types/src/supabase.ts
(15 hunks)
✅ Files skipped from review due to trivial changes (4)
- packages/ai/src/scheduling/default.ts
- packages/ai/src/scheduling/templates.ts
- packages/ai/src/scheduling/types.ts
- packages/types/src/supabase.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/ai/package.json
🧰 Additional context used
🧬 Code Graph Analysis (5)
apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx (4)
packages/ai/src/scheduling/types.ts (1)
Event
(8-16)packages/ui/src/components/ui/card.tsx (5)
Card
(68-68)CardHeader
(72-72)CardTitle
(73-73)CardDescription
(70-70)CardContent
(69-69)packages/ui/src/components/ui/badge.tsx (1)
Badge
(49-49)packages/ui/src/components/ui/tooltip.tsx (3)
Tooltip
(60-60)TooltipTrigger
(60-60)TooltipContent
(60-60)
apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx (4)
packages/ai/src/scheduling/types.ts (1)
TemplateScenario
(45-50)packages/ui/src/components/ui/card.tsx (5)
Card
(68-68)CardHeader
(72-72)CardTitle
(73-73)CardDescription
(70-70)CardContent
(69-69)packages/ai/src/scheduling/templates.ts (1)
templateScenarios
(4-737)packages/ui/src/components/ui/badge.tsx (1)
Badge
(49-49)
apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx (5)
packages/ai/src/scheduling/types.ts (2)
Task
(18-27)Event
(8-16)packages/ui/src/components/ui/card.tsx (5)
Card
(68-68)CardHeader
(72-72)CardTitle
(73-73)CardDescription
(70-70)CardContent
(69-69)packages/ui/src/components/ui/badge.tsx (1)
Badge
(49-49)packages/ui/src/components/ui/tooltip.tsx (3)
Tooltip
(60-60)TooltipTrigger
(60-60)TooltipContent
(60-60)packages/ui/src/components/ui/select.tsx (5)
Select
(170-170)SelectTrigger
(178-178)SelectValue
(179-179)SelectContent
(171-171)SelectItem
(173-173)
packages/ai/src/scheduling/algorithm.ts (2)
packages/ai/src/scheduling/types.ts (6)
Task
(18-27)ActiveHours
(29-33)ScheduleResult
(40-43)Event
(8-16)Log
(35-38)DateRange
(3-6)packages/ai/src/scheduling/default.ts (1)
defaultActiveHours
(4-23)
packages/ai/src/scheduling/algorithm.test.ts (1)
packages/ai/src/scheduling/default.ts (2)
defaultActiveHours
(4-23)defaultTasks
(25-35)
🪛 GitHub Check: codecov/patch
apps/calendar/src/app/[locale]/(root)/page.tsx
[warning] 3-3: apps/calendar/src/app/[locale]/(root)/page.tsx#L3
Added line #L3 was not covered by tests
[warning] 5-5: apps/calendar/src/app/[locale]/(root)/page.tsx#L5
Added line #L5 was not covered by tests
[warning] 8-8: apps/calendar/src/app/[locale]/(root)/page.tsx#L8
Added line #L8 was not covered by tests
[warning] 17-21: apps/calendar/src/app/[locale]/(root)/page.tsx#L17-L21
Added lines #L17 - L21 were not covered by tests
apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx
[warning] 2-303: apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx#L2-L303
Added lines #L2 - L303 were not covered by tests
apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx
[warning] 2-354: apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx#L2-L354
Added lines #L2 - L354 were not covered by tests
apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx
[warning] 2-143: apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx#L2-L143
Added lines #L2 - L143 were not covered by tests
apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
[warning] 2-474: apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx#L2-L474
Added lines #L2 - L474 were not covered by tests
apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx
[warning] 2-343: apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx#L2-L343
Added lines #L2 - L343 were not covered by tests
packages/ai/src/scheduling/algorithm.ts
[warning] 10-11: packages/ai/src/scheduling/algorithm.ts#L10-L11
Added lines #L10 - L11 were not covered by tests
[warning] 13-13: packages/ai/src/scheduling/algorithm.ts#L13
Added line #L13 was not covered by tests
[warning] 16-21: packages/ai/src/scheduling/algorithm.ts#L16-L21
Added lines #L16 - L21 were not covered by tests
[warning] 23-25: packages/ai/src/scheduling/algorithm.ts#L23-L25
Added lines #L23 - L25 were not covered by tests
[warning] 27-32: packages/ai/src/scheduling/algorithm.ts#L27-L32
Added lines #L27 - L32 were not covered by tests
[warning] 34-35: packages/ai/src/scheduling/algorithm.ts#L34-L35
Added lines #L34 - L35 were not covered by tests
[warning] 38-40: packages/ai/src/scheduling/algorithm.ts#L38-L40
Added lines #L38 - L40 were not covered by tests
[warning] 43-45: packages/ai/src/scheduling/algorithm.ts#L43-L45
Added lines #L43 - L45 were not covered by tests
[warning] 47-52: packages/ai/src/scheduling/algorithm.ts#L47-L52
Added lines #L47 - L52 were not covered by tests
[warning] 55-61: packages/ai/src/scheduling/algorithm.ts#L55-L61
Added lines #L55 - L61 were not covered by tests
[warning] 64-69: packages/ai/src/scheduling/algorithm.ts#L64-L69
Added lines #L64 - L69 were not covered by tests
[warning] 71-72: packages/ai/src/scheduling/algorithm.ts#L71-L72
Added lines #L71 - L72 were not covered by tests
[warning] 74-80: packages/ai/src/scheduling/algorithm.ts#L74-L80
Added lines #L74 - L80 were not covered by tests
[warning] 83-88: packages/ai/src/scheduling/algorithm.ts#L83-L88
Added lines #L83 - L88 were not covered by tests
[warning] 90-94: packages/ai/src/scheduling/algorithm.ts#L90-L94
Added lines #L90 - L94 were not covered by tests
[warning] 96-97: packages/ai/src/scheduling/algorithm.ts#L96-L97
Added lines #L96 - L97 were not covered by tests
[warning] 99-103: packages/ai/src/scheduling/algorithm.ts#L99-L103
Added lines #L99 - L103 were not covered by tests
[warning] 105-105: packages/ai/src/scheduling/algorithm.ts#L105
Added line #L105 was not covered by tests
apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx
[warning] 2-406: apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx#L2-L406
Added lines #L2 - L406 were not covered by tests
apps/calendar/src/app/[locale]/(root)/navbar.tsx
[warning] 63-63: apps/calendar/src/app/[locale]/(root)/navbar.tsx#L63
Added line #L63 was not covered by tests
apps/calendar/src/app/[locale]/layout.tsx
[warning] 116-116: apps/calendar/src/app/[locale]/layout.tsx#L116
Added line #L116 was not covered by tests
🪛 GitHub Check: CodeFactor
apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx
[notice] 129-129: apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx#L129
Unresolved 'todo' comment. (eslint/no-warning-comments)
packages/ai/src/scheduling/algorithm.test.ts
[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: Deploy-Preview
- GitHub Check: Verify generated types
- GitHub Check: Deploy-Preview
- GitHub Check: Deploy-Preview
🔇 Additional comments (3)
apps/calendar/src/app/[locale]/(root)/navbar.tsx (1)
63-63
: Verify thatSharedNavbar
forwardsclassName
className="bg-background"
will have no visual effect unlessSharedNavbar
explicitly spreads theclassName
prop to its root element. Double-check the underlying component to be certain the new style is actually applied.packages/ai/src/scheduling/algorithm.test.ts (1)
42-44
: Duration unit is unclear
duration: 120 // 2 hours in minutes
conflicts with the rest of the codebase whereduration
seems to be expressed in hours (seedefaultTasks
, whereduration: 1
equals 1 hour). Standardise on a single unit to avoid subtle bugs when the algorithm consumes these objects.apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx (1)
65-75
: Possible unit mismatch betweentask.duration
andscheduledDuration
.
totalDuration
is aggregated fromtask.duration
(unit unknown) whilescheduledDuration
is derived viadayjs.diff(..., 'hour', true)
(clearly hours). Iftask.duration
is stored in minutes or milliseconds, the metrics (average size, utilization, etc.) become inconsistent.Verify that both use the same time-unit, or normalise during aggregation:
-const totalDuration = tasks.reduce((sum, task) => sum + task.duration, 0); +const totalDuration = tasks.reduce( + (sum, task) => sum + dayjs.duration(task.duration).asHours(), // example normalisation + 0, +);
{DEV_MODE && ( | ||
<Link href="/scheduler"> | ||
<Button>Scheduler</Button> | ||
</Link> | ||
)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Locale is dropped from the Scheduler link – navigation will break
Link
points to "/scheduler"
, ignoring the active locale segment (/en
, /vi
, …). Users will be routed to the default-locale page, losing translation context.
-<Link href="/scheduler">
+<Link href={`/${locale}/scheduler`}>
If you rely on next-intl’s <Link locale={false|...}>
API, use that instead.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
{DEV_MODE && ( | |
<Link href="/scheduler"> | |
<Button>Scheduler</Button> | |
</Link> | |
)} | |
{DEV_MODE && ( | |
<Link href={`/${locale}/scheduler`}> | |
<Button>Scheduler</Button> | |
</Link> | |
)} |
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 17-21: apps/calendar/src/app/[locale]/(root)/page.tsx#L17-L21
Added lines #L17 - L21 were not covered by tests
🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/page.tsx around lines 17 to 21, the
Link to "/scheduler" does not include the active locale segment, causing
navigation to lose translation context. Update the Link component to preserve
the current locale by using next-intl's locale-aware Link API, such as adding
the locale prop or setting locale={false} to keep the current locale in the URL.
const updateFormData = (field: string, value: string | number) => { | ||
setFormData((prev) => ({ ...prev, [field]: value })); | ||
if (errors[field]) { | ||
setErrors((prev) => ({ ...prev, [field]: '' })); | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Guard against NaN
when numeric inputs are cleared
parseFloat(e.target.value)
returns NaN
on an empty field, causing NaN <= 0
checks and later arithmetic to behave unexpectedly.
Add an explicit empty-string check before calling parseFloat
, or fall back to ''
in state and coerce only during validation.
🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx
around lines 139 to 144, the updateFormData function does not guard against NaN
values when numeric inputs are cleared, causing issues with comparisons and
arithmetic. Modify the input handling to explicitly check if the input value is
an empty string before parsing it with parseFloat, and store an empty string in
state in that case. Only coerce the value to a number during validation to avoid
NaN propagation.
const addTask = (taskData: Omit<Task, 'id' | 'events'>) => { | ||
const newTask: Task = { | ||
...taskData, | ||
id: `task-${Date.now()}`, | ||
events: [], | ||
}; | ||
setTasks([...tasks, newTask]); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use collision-safe IDs
id: \
task-${Date.now()}`risks clashes when tasks are added rapidly. Prefer
crypto.randomUUID()(native) or
nanoid` for uniqueness.
🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx around lines 71 to
78, the task ID generation using `task-${Date.now()}` can cause collisions if
tasks are added quickly. Replace this with a collision-safe method by using
`crypto.randomUUID()` to generate the task ID, ensuring each ID is unique even
when tasks are created rapidly.
type="number" | ||
step="0.25" | ||
min="0.25" | ||
value={task.duration} | ||
onChange={(e) => | ||
onUpdateTask(task.id, { | ||
duration: parseFloat(e.target.value), | ||
}) | ||
} | ||
className="text-sm" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Persisting NaN
durations corrupts scheduling
Empty or non-numeric input pushes NaN
into task state, later breaking the algorithm.
Validate the value before calling onUpdateTask
, or coerce with Number(e.target.value || 0.25)
.
🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
around lines 346 to 355, the onChange handler for the duration input can pass
NaN to onUpdateTask if the input is empty or non-numeric, corrupting the task
state. Fix this by validating the input value before calling onUpdateTask,
ensuring it is a valid number, or coerce it using Number(e.target.value || 0.25)
to default to 0.25 when the input is invalid or empty.
const progressPercentage = progress | ||
? (progress.completed / task.duration) * 100 | ||
: 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Division by zero when task.duration === 0
progress.completed / task.duration
yields Infinity
.
Guard with Math.max(task.duration, 0.01)
or simply skip the bar when duration is zero.
🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
around lines 214 to 216, the calculation of progressPercentage divides
progress.completed by task.duration without checking if task.duration is zero,
which can cause a division by zero and result in Infinity. Fix this by guarding
the division with Math.max(task.duration, 0.01) to avoid zero division or by
skipping the progress bar rendering entirely when task.duration is zero.
// Ensure the part start time is rounded to 15-minute increment | ||
const partStart = roundToQuarterHour(slot.start, false); | ||
const partEnd = partStart.add(partDuration, 'hour'); | ||
|
||
// Verify the end time doesn't exceed the slot | ||
if (partEnd.isAfter(slot.end)) { | ||
const adjustedDuration = slot.end.diff(partStart, 'hour', true); | ||
|
||
if (adjustedDuration < adjustedTask.minDuration) { | ||
logs.push({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
partDuration
may round down to 0 h
hoursToQuarterHours(0.12)
⇒ 0.
After rounding, ensure partDuration ≥ 0.25
or bail with an explicit error to avoid infinite loops.
🤖 Prompt for AI Agents
In packages/ai/src/scheduling/algorithm.ts around lines 165 to 174, the
calculation of partDuration using hoursToQuarterHours may round down to zero,
causing potential infinite loops. After computing partDuration, add a check to
ensure it is at least 0.25 hours; if it is less, either set it to 0.25 or throw
an explicit error to prevent further processing with an invalid duration.
while (remainingDuration > 0 && attempts < maxAttempts) { | ||
attempts++; | ||
|
||
const availableSlots = getAvailableSlots( | ||
availableTimes[task.category], | ||
categoryHours, | ||
scheduledEvents | ||
); | ||
|
||
if (availableSlots.length === 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
maxAttempts = 50
can truncate large, perfectly schedulable tasks
A 25 h task split into 0.5 h parts needs 50 iterations plus one; the loop aborts even when slots exist.
Either calculate Math.ceil(duration / minDuration)
or remove the guard once slot progress is observed.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 96-97: packages/ai/src/scheduling/algorithm.ts#L96-L97
Added lines #L96 - L97 were not covered by tests
[warning] 99-103: packages/ai/src/scheduling/algorithm.ts#L99-L103
Added lines #L99 - L103 were not covered by tests
[warning] 105-105: packages/ai/src/scheduling/algorithm.ts#L105
Added line #L105 was not covered by tests
🤖 Prompt for AI Agents
In packages/ai/src/scheduling/algorithm.ts around lines 96 to 105, the loop uses
a fixed maxAttempts of 50 which can prematurely stop scheduling large tasks
split into many small parts. To fix this, replace the fixed maxAttempts with a
dynamic calculation like Math.ceil(duration / minDuration) to ensure enough
iterations for all parts, or modify the loop to continue if progress is being
made in scheduling slots, removing the arbitrary iteration limit.
const adjustedTask = { | ||
...task, | ||
duration: hoursToQuarterHours(task.duration), | ||
minDuration: ensureMinimumDuration(task.minDuration), | ||
maxDuration: hoursToQuarterHours(task.maxDuration), | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate duration relationships upfront
minDuration
, maxDuration
, and duration
are blindly adjusted; invalid configurations (e.g. min > max
or max > duration
) can create impossible constraints and endless retries.
Add an early sanity check and push a single error
log instead of looping 50 times.
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 83-88: packages/ai/src/scheduling/algorithm.ts#L83-L88
Added lines #L83 - L88 were not covered by tests
🤖 Prompt for AI Agents
In packages/ai/src/scheduling/algorithm.ts around lines 83 to 88, the code
adjusts task durations without validating their logical relationships, which can
cause impossible constraints and repeated retries. Add a validation step after
adjusting durations to check that minDuration is not greater than maxDuration
and maxDuration is not greater than duration. If these conditions fail, log a
single error message and handle the invalid configuration early to prevent
looping retries.
const splitTasks = new Set( | ||
events | ||
.filter((e) => e.partNumber && e.partNumber > 1) | ||
.map((e) => e.taskId) | ||
).size; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
splitTasks
under-counts tasks that are split.
Filtering on partNumber > 1
ignores the first part of a split task; tasks split into exactly two parts will contribute only one event (partNumber === 1
) and will therefore be missed.
Use > 0
(or presence of partNumber !== undefined
) then new Set
to deduplicate:
-.filter((e) => e.partNumber && e.partNumber > 1)
+.filter((e) => e.partNumber != null)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const splitTasks = new Set( | |
events | |
.filter((e) => e.partNumber && e.partNumber > 1) | |
.map((e) => e.taskId) | |
).size; | |
const splitTasks = new Set( | |
events | |
.filter((e) => e.partNumber != null) | |
.map((e) => e.taskId) | |
).size; |
🤖 Prompt for AI Agents
In
apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx
around lines 76 to 81, the calculation of splitTasks undercounts tasks because
it filters events with partNumber > 1, missing the first part of split tasks. To
fix this, change the filter condition to include all events with partNumber > 0
or partNumber defined, then use new Set to deduplicate taskIds, ensuring all
split tasks are counted correctly.
const workingHours = 8; // Assume 8-hour work day | ||
const utilizationRate = Math.min( | ||
(scheduledDuration / workingHours) * 100, | ||
100 | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
utilizationRate
can exceed 100 % across multi-day schedules.
The divisor is a hard-coded 8-hour day, but scheduledDuration
may span several days. Divide by workingHours * activeDays
(or the available window) to avoid inflated percentages.
-const workingHours = 8;
-const utilizationRate = Math.min(
- (scheduledDuration / workingHours) * 100,
- 100
-);
+const activeDays =
+ new Set(events.map(e => e.range.start.format('YYYY-MM-DD'))).size || 1;
+const utilizationRate = Math.min(
+ (scheduledDuration / (8 * activeDays)) * 100,
+ 100,
+);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const workingHours = 8; // Assume 8-hour work day | |
const utilizationRate = Math.min( | |
(scheduledDuration / workingHours) * 100, | |
100 | |
); | |
const activeDays = | |
new Set(events.map(e => e.range.start.format('YYYY-MM-DD'))).size || 1; | |
const utilizationRate = Math.min( | |
(scheduledDuration / (8 * activeDays)) * 100, | |
100, | |
); |
🤖 Prompt for AI Agents
In
apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx
around lines 113 to 117, the utilizationRate calculation incorrectly divides
scheduledDuration by a fixed 8-hour workday, causing values to exceed 100% for
multi-day schedules. Modify the divisor to be workingHours multiplied by the
number of activeDays (or the total available scheduling window) to correctly
reflect utilization over multiple days and prevent inflated percentages.
Summary by CodeRabbit