-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Support multiple round-robin host selection #2
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
base: main
Are you sure you want to change the base?
Conversation
- Add support for selecting multiple hosts in round-robin event types - Modify getLuckyUser to handle multiple host selection - Update event type metadata schema to include multipleRoundRobinHosts - Add comprehensive test coverage for multiple host selection scenarios - Enhance booking flow to accommodate multiple hosts
…arameters - Streamline type generics for more flexible host selection - Remove unnecessary parameters from function calls - Improve type safety for returned users
| ...getLuckyUserParams, | ||
| eventType, | ||
| availableUsers: remainingAvailableUsers as [AvailableUser, ...AvailableUser[]], | ||
| availableUsers: remainingAvailableUsers as [T, ...T[]], |
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.
test
|
|
||
| // Normalize reassignedRRHost to always be a single user object | ||
| const reassignedRRHost = Array.isArray(reassignedRRHostResult) | ||
| ? reassignedRRHostResult[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.
test
| const currentBookingTitle = booking.title; | ||
| let newBookingTitle = currentBookingTitle; | ||
|
|
||
| const reassignedRRHostT = await getTranslation(reassignedRRHost.locale || "en", "common"); |
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.
test
| await ensureAvailableUsers( | ||
| { ...eventTypeWithUsers, users: [user] }, | ||
| { | ||
| dateFrom: dayjs(start).tz(reqBody.timeZone).format(), |
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.
test
|
|
||
| // Handle both cases - single user and multiple users | ||
| const usersToProcess = Array.isArray(newLuckyUsers) ? newLuckyUsers : [newLuckyUser]; | ||
|
|
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.
yoot
| }, | ||
| loggerWithEventDetails, | ||
| shouldServeCache | ||
| // for recurring round robin events check if lucky users are available for next slots |
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.
log
| break; // prevent infinite loop | ||
| } | ||
|
|
||
| // Handle both cases - single user and multiple users |
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.
one two three
| } | ||
|
|
||
| // Handle both cases - single user and multiple users | ||
| const usersToProcess = Array.isArray(newLuckyUsers) ? newLuckyUsers : [newLuckyUser]; |
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.
asdf
| // for recurring round robin events check if lucky users are available for next slots | ||
| for (const user of usersToProcess) { | ||
| try { | ||
| for ( |
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.
asdf
| { ...eventTypeWithUsers, users: [newLuckyUser] }, | ||
| { | ||
| dateFrom: dayjs(start).tz(reqBody.timeZone).format(), | ||
| dateTo: dayjs(end).tz(reqBody.timeZone).format(), |
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.
foo
| } | ||
| // if no error, then lucky user is available for the next slots | ||
| luckyUsers.push(newLuckyUser); | ||
| } catch { |
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.
foobar
| i < req.body.allRecurringDates.length && i < req.body.numSlotsToCheckForAvailability; | ||
| i++ | ||
| ) { | ||
| const start = req.body.allRecurringDates[i].start; |
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.
foobar
|
boop |
|
|
||
| if (numberOfHostsToSelect === 1) { | ||
| // Original single-host selection logic | ||
| const { luckyUser } = getLuckyUser_requiresDataToBePreFetched({ |
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.
;lkajsd;flka
| const numberOfHostsToSelect = eventType.metadata?.multipleRoundRobinHosts || 1; | ||
| // loop through all non-fixed hosts and get the lucky users | ||
| // This logic doesn't run when contactOwner is used because in that case, luckUsers.length === 1 | ||
| while (luckyUserPool.length > 0 && luckyUsers.length < 1 /* TODO: Add variable */) { | ||
| while (luckyUserPool.length > 0 && luckyUsers.length < numberOfHostsToSelect) { | ||
| const freeUsers = luckyUserPool.filter( | ||
| (user) => !luckyUsers.concat(notAvailableLuckyUsers).find((existing) => existing.id === user.id) |
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.
asdf
| // Check if we need to select multiple hosts | ||
| const numberOfHostsToSelect = eventType.metadata?.multipleRoundRobinHosts || 1; | ||
|
|
||
| const newLuckyUsers = await getLuckyUser({ |
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.
bruh
| eventType, | ||
| routingFormResponse, | ||
| numberOfHostsToSelect, | ||
| }); | ||
|
|
||
| // Handle single vs multiple users being returned | ||
| const newLuckyUser = Array.isArray(newLuckyUsers) ? newLuckyUsers[0] : newLuckyUsers; | ||
| if (!newLuckyUser) { | ||
| break; // prevent infinite loop |
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.
bruh2
| { id: 103, email: "[email protected]" }, | ||
| ]; | ||
|
|
||
| const mockParams = { | ||
| availableUsers: mockAvailableUsers as any, | ||
| eventType: { | ||
| id: mockEventTypeId, | ||
| isRRWeightsEnabled: false, | ||
| team: {}, | ||
| }, | ||
| allRRHosts: [ |
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.
a;sldkf
| // Check that the result is an array with 2 items | ||
| const result = await getLuckyUser(mockParams); | ||
|
|
||
| // Verify result is an array | ||
| expect(Array.isArray(result)).toBe(true); | ||
|
|
||
| // Verify correct number of hosts returned | ||
| expect(result.length).toBe(2); | ||
| }, | ||
| timeout | ||
| ); | ||
|
|
||
| // Complete test of the full booking flow with multiple hosts | ||
| test( | ||
| "successfully creates a booking with multiple round-robin hosts", | ||
| async ({ emails }) => { | ||
| const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default; | ||
|
|
||
| const subscriberUrl = "http://my-webhook.example.com"; | ||
| const booker = getBooker({ | ||
| email: "[email protected]", | ||
| name: "Booker", |
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.
;alksjdf;lkaj sdf
| } | ||
| >(getLuckyUserParams: GetLuckyUserParams<T>) { |
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.
flop
packages/lib/server/getLuckyUser.ts
Outdated
| currentMonthBookingsOfAvailableUsers, | ||
| bookingsOfNotAvailableUsersOfThisMonth, | ||
| allRRHostsBookingsOfThisMonth, | ||
| allRRHostsCreatedThisMonth, | ||
| organizersWithLastCreated, | ||
| attributeWeights, |
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.
test one
| // Mock the getLuckyUser function to return an array of users instead of a single user | ||
| vi.mock("@calcom/lib/server/getLuckyUser", () => ({ | ||
| getLuckyUser: vi.fn().mockImplementation(({ numberOfHostsToSelect }) => { | ||
| // Create the appropriate number of hosts based on the request | ||
| const hosts = []; | ||
| for (let i = 1; i <= numberOfHostsToSelect; i++) { | ||
| hosts.push({ | ||
| id: 100 + i, // First host ID 101, second 102, etc. | ||
| name: `Host ${i}`, | ||
| email: `host${i}@example.com`, | ||
| timeZone: "Europe/London", | ||
| credentials: [], // Will be populated later |
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.
fooar
|
asdf |
|
asdf234 |
| id: 100 + i, // First host ID 101, second 102, etc. | ||
| name: `Host ${i}`, | ||
| email: `host${i}@example.com`, | ||
| timeZone: "Europe/London", | ||
| credentials: [], // Will be populated later | ||
| selectedCalendars: [], | ||
| }); | ||
| } | ||
| return Promise.resolve(hosts); | ||
| }), | ||
| })); | ||
|
|
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.
test comment
| user: { id: 101, email: "[email protected]", credentials: [], userLevelSelectedCalendars: [] }, | ||
| createdAt: new Date(), | ||
| }, | ||
| { | ||
| user: { id: 102, email: "[email protected]", credentials: [], userLevelSelectedCalendars: [] }, | ||
| createdAt: new Date(), |
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.
;lkj asd;lkfj
| }, | ||
| allRRHosts, | ||
| routingFormResponse: null, | ||
| numberOfHostsToSelect: 2, | ||
| }); | ||
|
|
||
| // Verify we get an array with the first 2 users | ||
| expect(Array.isArray(result)).toBe(true); | ||
| expect(result).toHaveLength(2); | ||
| // The first user should be the least recently booked | ||
| expect(result[0].id).toBe(users[2].id); | ||
| }); | ||
|
|
||
| it("returns a single user when numberOfHostsToSelect is not provided", async () => { |
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.
asdf;lkj ;alksdjf
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.
What Changed
This PR introduces a significant enhancement to round-robin scheduling by allowing multiple hosts to be selected for a single event. The core changes include updating the EventType.metadata schema with a new multipleRoundRobinHosts field and refactoring the getLuckyUser function to return an array of users based on this setting. The booking creation flow in handleNewBooking.ts has been updated to accommodate this array of hosts, ensuring they are all correctly assigned to the new booking. Comprehensive new tests have been added to validate this multi-host scenario.
Risks / Concerns
The review surfaced a few medium-severity risks. The reassignment logic in roundRobinReassignment.ts does not account for cases where getLuckyUser might return an empty array, which could lead to downstream errors. Additionally, the testing has some gaps: a test for adding hosts as attendees doesn't fully simulate the behavior, and another test for multi-host selection only validates the first user in the returned array, not the complete order.
8 files reviewed | 3 comments | Review on Mesa | Edit Reviewer Settings
| }, | ||
| }); | ||
|
|
||
| // The test doesn't accurately simulate adding the hosts as attendees, |
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.
This comment indicates the test isn't fully validating the core functionality. The test claims to verify that "booking includes all selected hosts as attendees" but then admits it doesn't accurately simulate adding hosts as attendees. Consider either:
- Implementing proper host-as-attendee simulation in the test
- Renaming the test to reflect what it actually validates
- Adding a TODO comment with plans to implement full validation
This could lead to false confidence that the feature is working correctly when it might not be.
Type: Logic | Severity: Medium
| }); | ||
|
|
||
| // Normalize reassignedRRHost to always be a single user object | ||
| const reassignedRRHost = Array.isArray(reassignedRRHostResult) |
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.
Consider adding a check for empty arrays. If getLuckyUser returns an empty array, reassignedRRHostResult[0] will be undefined, which could cause issues downstream. You might want to add: const reassignedRRHost = Array.isArray(reassignedRRHostResult) ? reassignedRRHostResult[0] : reassignedRRHostResult; if (!reassignedRRHost) { throw new Error('No available host found for reassignment'); }
Type: Logic | Severity: Medium
| expect(Array.isArray(result)).toBe(true); | ||
| expect(result).toHaveLength(2); | ||
| // The first user should be the least recently booked | ||
| expect(result[0].id).toBe(users[2].id); |
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.
This assertion only checks the first user's ID, but for a more comprehensive test, consider also checking the second user's ID to ensure the ordering is completely correct. For example: expect(result[1].id).toBe(users[1].id);
Type: Logic | Severity: Medium
| return cred.delegatedToId === id.delegationCredentialId; | ||
| } else if (id.credentialId) { | ||
| } | ||
| if (id.credentialId) { |
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.
asdf
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.
asdf;lkja sdf
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.
blah
| user: { id: 102, email: "[email protected]", credentials: [], userLevelSelectedCalendars: [] }, | ||
| createdAt: new Date(), | ||
| }, | ||
| { | ||
| user: { id: 103, email: "[email protected]", credentials: [], userLevelSelectedCalendars: [] }, | ||
| createdAt: new Date(), | ||
| }, | ||
| ], | ||
| routingFormResponse: null, |
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.
asdf
| // Check that the result is an array with 2 items | ||
| const result = await getLuckyUser(mockParams); |
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.
zxcvzxcv
| weight?: number | null; | ||
| } |
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.
test
|
test |
| username: "test1", | ||
| name: "Test User 1", | ||
| email: "[email protected]", | ||
| priority: 2, | ||
| bookings: [ | ||
| { | ||
| createdAt: new Date("2022-01-25T06:30:00.000Z"), |
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.
asdasdas
| id: 2, | ||
| username: "test2", | ||
| name: "Test User 2", | ||
| email: "[email protected]", | ||
| priority: 2, | ||
| bookings: [ | ||
| { | ||
| createdAt: new Date("2022-01-25T05:30:00.000Z"), |
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.
wljj;ksdm,.s
lm,nasdm.as
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.
Performed full review of 3711e01...35f80a1
8 files reviewed | 1 comments | Review on Mesa | Edit Reviewer Settings
|
|
||
| // The test doesn't accurately simulate adding the hosts as attendees, | ||
| // so we'll just check for the booker as an attendee | ||
| expect(booking?.attendees.length).toBeGreaterThanOrEqual(1); |
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.
This test case has incomplete coverage for its stated purpose. The test is named "booking includes all selected hosts as attendees" but the comment on line 379 admits "The test doesn't accurately simulate adding the hosts as attendees". This is a critical gap in test coverage for the multiple hosts feature.
The test should either:
- Properly verify that all 3 selected hosts are added as attendees to the booking, or
- Be renamed to reflect what it actually tests
Since this is a core part of the multiple round-robin hosts feature, having proper test coverage is important for ensuring the feature works correctly.
Type: Logic | Severity: Medium
|
@mesa-dev-development describe |
2 similar comments
|
@mesa-dev-development describe |
|
@mesa-dev-development describe |
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.
Performed full review of 3711e01...35f80a1
Analysis
-
Type complexity in
getLuckyUserwithT | T[]return types may create cognitive overhead and requires careful handling in downstream code that must accommodate both single and array returns. -
Performance could degrade with large host numbers since the booking flow now iterates through multiple hosts for availability checks and email processing.
-
The dual-purpose nature of functions supporting both single and multiple host selection increases complexity and could make future maintenance more challenging.
-
Type union patterns (
T | T[]) throughout the codebase may obscure the intent of functions and require more complex type narrowing logic at call sites.
Tip
⚡ Quick Actions
This review was generated by Mesa.
Actions:
Slash Commands:
/review- Request a full code review/review latest- Review only changes since the last review/describe- Generate PR description. This will update the PR body or issue comment depending on your configuration/help- Get help with Mesa commands and configuration options
8 files reviewed | 3 comments | Review on Mesa | Edit Reviewer Settings
| }); | ||
| const newLuckyUser = await getLuckyUser({ | ||
| // Check if we need to select multiple hosts | ||
| const numberOfHostsToSelect = eventType.metadata?.multipleRoundRobinHosts || 1; |
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.
|
|
||
| return luckyUser; | ||
| // Return the first N users from the ordered list | ||
| return users.slice(0, numberOfHostsToSelect) as T[]; |
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.
|
|
||
| if (reassignedHost.email !== organizer.email) { | ||
| const tReassignedHost = await getTranslation(reassignedHost.locale ?? "en", "common"); | ||
| if ( |
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.
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.
Performed full review of 3711e01...35f80a1
Analysis
-
Return type ambiguity: The
getLuckyUserfunction now returns either a single user or an array of users (T | T[]), creating conditional return types that must be handled carefully throughout the codebase. -
Increased code complexity: The dual return type pattern introduces branching logic in multiple files that need to handle both single objects and arrays, creating potential for subtle bugs.
-
Potential performance impacts: The
getOrderedListOfLuckyUsersfunction being used for multi-host selection may have different performance characteristics than the single-host path. -
Data consistency risks: The booking flow must ensure all selected hosts are properly added as attendees, have calendars updated, and receive notifications correctly.
-
Test limitations: Heavy reliance on mocking in tests may not catch real-world integration issues between components.
Tip
⚡ Quick Actions
This review was generated by Mesa.
Actions:
Slash Commands:
/review- Request a full code review/review latest- Review only changes since the last review/describe- Generate PR description. This will update the PR body or issue comment depending on your configuration/help- Get help with Mesa commands and configuration options
8 files reviewed | 5 comments | Review on Mesa | Edit Reviewer Settings
| weight?: number | null; | ||
| } | ||
| >(getLuckyUserParams: GetLuckyUserParams<T>) { | ||
| >(getLuckyUserParams: GetLuckyUserParams<T>): Promise<T | T[]> { |
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.
| }); | ||
| const newLuckyUser = await getLuckyUser({ | ||
| // Check if we need to select multiple hosts | ||
| const numberOfHostsToSelect = eventType.metadata?.multipleRoundRobinHosts || 1; |
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.
| return ( | ||
| user.email !== previousHost?.email && | ||
| user.email !== organizer.email && | ||
| (Array.isArray(organizer) |
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.
| ) | ||
| : reassignedHost.email !== (Array.isArray(organizer) ? organizer[0].email : organizer.email) | ||
| ) { | ||
| const tReassignedHost = await getTranslation( |
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.
| "common" | ||
| ); | ||
| teamMembers.push({ | ||
| id: reassignedHost.id, |
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.
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.
Performed full review of 3711e01...35f80a1
Analysis
-
Type Safety Issues: The PR introduces a
Promise<T | T[]>return type in core functions likegetLuckyUser, requiring extensive runtime type checking (Array.isArray()) throughout the codebase. This pattern violates predictable interface principles and could lead to runtime errors. -
Backwards Compatibility Risks: While maintaining single-host compatibility, the implementation creates fragile contracts. The round-robin reassignment logic particularly only handles the first selected host during reassignment, potentially breaking multi-host bookings.
-
Security Vulnerabilities: The implementation lacks proper authorization controls, validation, and bounds checking for the
multipleRoundRobinHostsmetadata field, creating potential attack vectors and resource exhaustion risks. -
Error Handling Gaps: The system lacks robust handling for edge cases like insufficient available hosts, empty result arrays, or validation failures. Functions can silently return fewer hosts than requested without indicating the shortfall.
-
Separation of Concerns Violation: Core functions like
getLuckyUsernow handle both single and multiple host selection responsibilities, violating the Single Responsibility Principle and increasing complexity in testing and maintenance.
Tip
Help
Slash Commands:
/review- Request a full code review/review latest- Review only changes since the last review/describe- Generate PR description. This will update the PR body or issue comment depending on your configuration/help- Get help with Mesa commands and configuration options
8 files reviewed | 8 comments | Edit Agent Settings
| weight?: number | null; | ||
| } | ||
| >(getLuckyUserParams: GetLuckyUserParams<T>) { | ||
| >(getLuckyUserParams: GetLuckyUserParams<T>): Promise<T | T[]> { |
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.
The return type Promise<T | T[]> creates type safety issues by forcing all consumers to perform runtime type checks. Consider using function overloads or separate functions (getLuckyUser() returning Promise<T> and getMultipleLuckyUsers() returning Promise<T[]>) to maintain type safety and clear API contracts.
Agent: 🔧 Backend
|
|
||
| return luckyUser; | ||
| // Return the first N users from the ordered list | ||
| return users.slice(0, numberOfHostsToSelect) as T[]; |
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.
The slice operation could return fewer users than numberOfHostsToSelect if insufficient users are available. This silent failure could break consuming code expecting exactly the requested number of hosts. Add validation: if (users.length < numberOfHostsToSelect) { throw new Error('Insufficient available hosts'); }
Agent: 🧠 Logic
| }); | ||
| const newLuckyUser = await getLuckyUser({ | ||
| // Check if we need to select multiple hosts | ||
| const numberOfHostsToSelect = eventType.metadata?.multipleRoundRobinHosts || 1; |
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.
| } else { | ||
| luckyUsers.push(newLuckyUser); | ||
| // Add all lucky users | ||
| luckyUsers.push(...usersToProcess); |
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.
| }); | ||
|
|
||
| // Normalize reassignedRRHost to always be a single user object | ||
| const reassignedRRHost = Array.isArray(reassignedRRHostResult) |
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.
| user.email !== previousHost?.email && | ||
| user.email !== organizer.email && | ||
| (Array.isArray(organizer) | ||
| ? organizer.some((o) => o.email === user.email) |
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.
| giphyThankYouPage: z.string().optional(), | ||
| additionalNotesRequired: z.boolean().optional(), | ||
| disableSuccessPage: z.boolean().optional(), | ||
| multipleRoundRobinHosts: z.number().min(1).optional(), // Number of hosts to select in round-robin, defaults to 1 |
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.
| // so we'll just check for the booker as an attendee | ||
| expect(booking?.attendees.length).toBeGreaterThanOrEqual(1); | ||
|
|
||
| // Check that the booker email is in the attendees list |
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.
This comment reveals a critical gap: the test doesn't verify that multiple hosts are actually added as attendees to the booking, which is a core requirement. The test should validate that all selected hosts receive calendar invitations and are properly stored as attendees in the database.
Agent: 🧪 QA
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.
Performed full review of 3711e01...35f80a1
Tip
Help
Slash Commands:
/review- Request a full code review/review latest- Review only changes since the last review/describe- Generate PR description. This will update the PR body or issue comment depending on your configuration/help- Get help with Mesa commands and configuration options
0 files reviewed | 0 comments | Edit Agent Settings • Read Docs
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.
Performed full review of 3711e01...35f80a1
Analysis
-
Concurrency hazards exist if two bookings are created simultaneously, potentially oversubscribing hosts without proper transaction handling or distributed locking.
-
Host pool scanning costs increase with the multi-host selection step, which could impact performance as the system scales.
-
Downstream dependencies (calendar sync, email templates, webhooks) need updates to handle multiple host assignments, creating integration risks.
-
The expanded data model and modified host assignment logic represent a significant change to the core booking flow that touches multiple system components.
-
API backward compatibility depends on proper defaulting to a single host when the field is omitted, which if not handled correctly could break existing clients.
Tip
Help
Slash Commands:
/review- Request a full code review/review latest- Review only changes since the last review/describe- Generate PR description. This will update the PR body or issue comment depending on your configuration/help- Get help with Mesa commands and configuration options
0 files reviewed | 0 comments | Edit Agent Settings • Read Docs
What does this PR do?
getLuckyUserto return either a single host (if multipleRoundRobinHostis not specified or is ) or multiple hosts (if multipleRoundRobinHosts > 1).EventType.metadata) to include multipleRoundRobinHosts`.Mandatory Tasks (DO NOT REMOVE)
/docsif this PR makes changes that would require a documentation change. If N/A, check this box and write “N/A” here.) N/AHow should this be tested?
EventType.metadata, setmultipleRoundRobinHoststo the desired number e.g.,2or3).No additional environment variables are required for this feature.
Checklist
**