fix(booking): scheduling-timezone limit buckets, guarded + idempotent allocation, requested-path parity - #998
Conversation
… allocation, requested-path parity Unify every daily/weekly limit bucket on the event's schedulingTimezone (default Asia/Kolkata) via shared SlotCalculationService keys across the client guards, the client auto-allocator, and the server validators (ADR B9); add the initialAllocation multi-tab 409 guard (ADR B10); send Idempotency-Key from all client allocate paths with 409 recovery UX; fix the requested-slots path ignoring plan totals and in-progress reschedule reductions; remove the callsPerWeek*4*months fallback; queue toasts through a single message catalog; extract the selection validators to a pure, unit-tested module. Part of the Request Calendar work tracked in #997. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
✅ Deploy Preview for familiarise ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Warning Review limit reached
Next review available in: 42 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughBooking allocation now uses explicit scheduling-timezone day/week keys across client and server validation, adds idempotent allocation attempts and an ChangesBooking allocation correctness
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive correctness sweep for the booking calendar system, aligning client-side guards, the auto-allocator, and server-side validators to use the event's scheduling timezone (ADR B9) and implementing an initialAllocation multi-tab guard (ADR B10) with idempotency key wiring. Review feedback suggests defensive improvements to prevent negative slot counts, optimizing map iterations in the newly extracted validation utility, and verifying that the Prisma namespace is properly imported to avoid compilation errors.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Actionable comments posted: 13
🤖 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 `@__tests__/booking-algorithm/initial-allocation-guard.test.ts`:
- Around line 70-85: Extend the initial-allocation guard tests for both manual
and auto modes so slotOfAppointment.count returns zero before allocation but a
transaction-scoped count reports confirmed slots. Assert the allocation returns
the typed 409 response and that no conflicting write proceeds, covering the
transaction race-window re-check rather than only the preliminary count path.
In `@__tests__/booking-algorithm/mode-parity.test.ts`:
- Around line 78-128: Update the mode-parity test cases around
AllocationAlgorithms.autoAllocate and the additional case to define one explicit
non-default schedulingTimezone, then pass it consistently through the allocation
options, validationOptions, validateEventSlots, validateSlotDistribution, and
groupSlotsByDay calls. Preserve the existing assertions while ensuring all modes
evaluate slots using the same explicit event timezone rather than the fallback.
- Around line 212-225: Extend the test to validate the authoritative
totalSessions behavior across requested, auto, and shared allocation modes,
including a five-week-bucket case where the four-session plan must not require
five calls. Update getSlotLimits and each relevant allocation path to forward
the plan’s maxTotalCalls into requiredSlots calculation, preserving consistent
plan-total parity across all modes.
In
`@app/dashboard/consultant/`[consultantId]/(features)/requests/RequestSlotAllocationTab.tsx:
- Around line 373-377: Update the attempt-key handling around the allocation
request and the related usage at the second location to use a ref instead of
React state, matching the shared allocation hook. Generate and store the key
synchronously in the ref before issuing the request, and reuse that ref value
across rapid successive clicks so both requests share the same idempotency key.
In
`@app/dashboard/consultant/`[consultantId]/(features)/shared/hooks/useSlotAllocation.ts:
- Around line 593-615: Convert slotLimits.maxSlots to the equivalent session
count before using it in the call-limit logic. Apply this consistently to
maxTotalCalls and the related declarations/usages around sessionAdded, including
the additional locations noted at 707-709, 787-798, and 810, so all comparisons
use sessions rather than 30-minute slots.
In
`@app/dashboard/consultant/`[consultantId]/(features)/shared/utils/allocationService.ts:
- Around line 27-32: Update the AllocationResponse interface to type data as an
array of allocation appointment DTOs matching result.appointments returned by
all allocation routes, replacing the date-keyed RawAvailabilityApiSlot record.
Reuse an existing appointment DTO type if available; otherwise define the
appropriate DTO near AllocationResponse, and update affected imports or
consumers to preserve the corrected contract.
In
`@app/dashboard/consultant/`[consultantId]/(features)/shared/utils/calendarUtils.ts:
- Around line 590-593: Update calendarUtils.ts lines 590-593 so day-based
validation and progress helpers accept and use the event scheduling timezone
when calling SlotCalculationService.dayKey. In UnifiedCalendar.tsx lines
193-218, pass that timezone into the final completed-call validation. In
UnifiedCalendar.tsx lines 580-608, replace browser-local toDateString() boundary
checks with scheduling-timezone dayKey comparisons.
In
`@app/dashboard/consultant/`[consultantId]/(features)/shared/utils/slotSelectionValidation.ts:
- Around line 586-819: Refactor validateEventSlots into a lightweight dispatcher
that preserves the shared empty-selection and common setup behavior, then
delegates webinar, class, subscription, and consultation validation to separate
focused validator functions. Move each event-specific branch and its related
weekly checks into the appropriate validator, preserving all existing
ValidationResult fields, errors, warnings, and validation behavior while
reducing validateEventSlots cognitive complexity below the allowed threshold.
- Around line 280-307: Update countSessionsForDay so each consecutive run is
evaluated independently and any run shorter than slotsPerSession is reported as
incomplete, rather than allowing leftovers to be combined across disconnected
runs. Propagate this incomplete-run state through the allocation-readiness
checks at the related subscription/class validation paths, and reject selections
containing any incomplete run even when total slot counts are divisible by
slotsPerSession.
In `@utils/slotAllocation/SlotAllocationService.ts`:
- Around line 265-296: Make assertNoConfirmedSlots atomic by acquiring an
event-scoped lock shared across auto, manual, and requested allocation modes
before counting confirmed slots, and hold that lock through the subsequent write
transaction. Apply the same locking/claiming behavior at every listed
initial-allocation call site so concurrent transactions cannot both pass the
zero-slot check and commit competing allocations.
- Around line 108-113: Update the requested-mode path in the switch and
useRequestedSlots to propagate request.idempotencyKey. Before the confirmed-slot
guard, detect and return the prior successful result for a matching key; within
the transaction, stamp the first existing appointment with the key when
processing the initial request so retries replay success instead of returning
409.
In `@utils/slotAllocation/SlotCalculationService.ts`:
- Around line 145-198: The recurring totals calculation still uses UTC week
boundaries while limit buckets use the scheduling timezone. In
utils/slotAllocation/SlotCalculationService.ts:145-198, update countWeeks and
its recurring-calculation callers to accept and use the scheduling timezone via
the existing week infrastructure. In utils/subscriptionValidation.ts:80-91, pass
schedulingTimezone into that calculation so maxTotalCalls aligns with generated
weekly buckets.
In `@utils/slotAllocation/SlotValidationService.ts`:
- Around line 1061-1065: Update the session-building loop in
SlotValidationService to create a chronological copy of slots before iterating
in slotsPerSession-sized steps. Sort the copy by slot start time while
preserving the original slots array, then use that sorted collection for dayKey
and subsequent session calculations.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 416c73c2-2657-4567-b9f1-62a92fd54d75
📒 Files selected for processing (33)
__tests__/booking-algorithm/allocationAlgorithms.test.ts__tests__/booking-algorithm/idempotency-key.test.ts__tests__/booking-algorithm/initial-allocation-guard.test.ts__tests__/booking-algorithm/mode-parity.test.ts__tests__/booking-algorithm/required-slots-periods.test.ts__tests__/booking-algorithm/slot-boundary-bucketing.test.ts__tests__/booking-algorithm/slotCalculationService.test.ts__tests__/booking-algorithm/subscriptionValidation.test.ts__tests__/booking-algorithm/toast-queue.test.tsapp/api/bookings/classes/[classId]/allocate/route.tsapp/api/bookings/consultations/[consultationId]/allocate/route.tsapp/api/bookings/subscriptions/[subscriptionId]/allocate/route.tsapp/api/bookings/webinars/[webinarId]/allocate/route.tsapp/dashboard/consultant/[consultantId]/(features)/requests/RequestSlotAllocationTab.tsxapp/dashboard/consultant/[consultantId]/(features)/requests/types.tsapp/dashboard/consultant/[consultantId]/(features)/shared/components/UnifiedCalendar.tsxapp/dashboard/consultant/[consultantId]/(features)/shared/hooks/useSlotAllocation.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/allocationAlgorithms.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/allocationMessages.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/allocationService.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/calendarUtils.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/slotSelectionValidation.tsdocs/booking/00-architecture-decisions.mddocs/booking/02-event-types-and-validation.mddocs/booking/03-slot-math-and-calculations.mddocs/booking/05-troubleshooting-and-changelog.mddocs/booking/14-local-development-and-testing.mdschemas/slotAllocation/validationSchemas.tsutils/slotAllocation/SlotAllocationService.tsutils/slotAllocation/SlotCalculationService.tsutils/slotAllocation/SlotValidationService.tsutils/slotAllocation/types.tsutils/subscriptionValidation.ts
…city, requested-mode idempotency CI: replace machine-local getDay() assertions with scheduling-timezone / UTC-explicit checks (suite now green under UTC, IST, and New York). Sonar: split validateEventSlots into per-event validators (complexity 49→dispatcher), explicit sort comparator, crypto-only key fallback, optional chains, readonly formatter cache, drop redundant jumps and an always-truthy guard. CodeRabbit: advisory xact lock makes the initialAllocation guard atomic across modes for lock-less group events; requested mode now replays and stamps Idempotency-Keys; the requests tab attempt key moves to a ref (double-click safe); allocation response typed as appointment DTOs; getSlotLimits honors the plan total; manual allocate rejects incomplete per-day runs; per-day cap sorts its input; scheduling timezone threaded into auto-expand and progress helpers. Adds race-window and non-default-timezone tests. Part of #998 review triage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ction narrowing lib.dom types every Crypto member as present, so an `in` check collapses the fallback branch to never; detect via optional access instead. Mock allocation data as an array to match the new DTO type. Part of #998 review triage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/dashboard/consultant/[consultantId]/(features)/shared/utils/slotSelectionValidation.ts (1)
184-202: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReduce
minSlotsby past confirmed slots too.
maxSlotsrepresents remaining calls, butminSlotsremains the full-plan slot count. An in-progress subscription can therefore require more slots than its maximum permits.Proposed fix
const pastSessions = Math.floor( (options.pastConfirmedSlotCount || 0) / subscriptionSessionSlots, ); + const remainingRequiredSlots = Math.max( + 0, + requiredSlots - (options.pastConfirmedSlotCount || 0), + ); return { - minSlots: requiredSlots, + minSlots: remainingRequiredSlots, maxSlots: Math.max(0, rawMaxCalls - pastSessions),🤖 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 `@app/dashboard/consultant/`[consultantId]/(features)/shared/utils/slotSelectionValidation.ts around lines 184 - 202, Update the subscription branch in the slot-selection validation logic so minSlots is reduced by options.pastConfirmedSlotCount, matching the remaining-session calculation used for maxSlots. Preserve the existing non-negative maxSlots behavior and ensure minSlots reflects only the remaining required slots for in-progress subscriptions.
♻️ Duplicate comments (1)
utils/slotAllocation/SlotCalculationService.ts (1)
145-198: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftRecurring totals still use UTC week counts while allocation limits use scheduling-timezone weeks.
utils/slotAllocation/SlotCalculationService.ts#L145-L198: extend the canonical timezone week infrastructure to covercountWeeks.app/dashboard/consultant/[consultantId]/(features)/shared/components/UnifiedCalendar.tsx#L503-L510: derive the fallback total with the event scheduling timezone.app/dashboard/consultant/[consultantId]/(features)/shared/utils/allocationAlgorithms.ts#L703-L714: calculatetotalWeeksusing the same timezone asslotsByWeek.utils/slotAllocation/SlotAllocationService.ts#L1542-L1547: use timezone-aware week counting for the server iteration bound.🤖 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 `@utils/slotAllocation/SlotCalculationService.ts` around lines 145 - 198, Recurring totals count weeks in UTC while allocation limits use the scheduling timezone. In utils/slotAllocation/SlotCalculationService.ts lines 145-198, add timezone-aware week-counting infrastructure alongside weekKey and startOfWeekSundayInTz, including a countWeeks API. Update UnifiedCalendar.tsx lines 503-510 to derive fallback totals with the event scheduling timezone, allocationAlgorithms.ts lines 703-714 to calculate totalWeeks using the same timezone as slotsByWeek, and SlotAllocationService.ts lines 1542-1547 to use timezone-aware week counting for the server iteration bound.
🤖 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
`@app/dashboard/consultant/`[consultantId]/(features)/shared/hooks/useSlotAllocation.ts:
- Around line 302-308: Update generateIdempotencyKey to replace the "randomUUID"
in crypto check with a typeof crypto.randomUUID === "function" check inside the
existing crypto availability guard, preserving the fallback getRandomValues
branch.
In
`@app/dashboard/consultant/`[consultantId]/(features)/shared/utils/slotSelectionValidation.ts:
- Around line 664-670: The aggregate validation incorrectly treats disconnected
slots on the same day as complete sessions. In slotSelectionValidation.ts lines
664-670, derive hasInProgress from the leftover slots in each consecutive run
rather than the day-total modulo; in allocationAlgorithms.ts lines 195-210,
validate every session-sized run for exact slot adjacency instead of validating
only the aggregate day count.
In `@utils/slotAllocation/SlotAllocationService.ts`:
- Around line 1081-1099: After acquiring the advisory event lock inside the
prisma.$transaction callback, call findIdempotentAllocation using the
transaction client before evaluating initialAllocation or
assertNoConfirmedSlotsInTx. Return the transaction-local replay result when
present, while preserving the existing guard for genuinely new allocations and
the pre-transaction replay check.
---
Outside diff comments:
In
`@app/dashboard/consultant/`[consultantId]/(features)/shared/utils/slotSelectionValidation.ts:
- Around line 184-202: Update the subscription branch in the slot-selection
validation logic so minSlots is reduced by options.pastConfirmedSlotCount,
matching the remaining-session calculation used for maxSlots. Preserve the
existing non-negative maxSlots behavior and ensure minSlots reflects only the
remaining required slots for in-progress subscriptions.
---
Duplicate comments:
In `@utils/slotAllocation/SlotCalculationService.ts`:
- Around line 145-198: Recurring totals count weeks in UTC while allocation
limits use the scheduling timezone. In
utils/slotAllocation/SlotCalculationService.ts lines 145-198, add timezone-aware
week-counting infrastructure alongside weekKey and startOfWeekSundayInTz,
including a countWeeks API. Update UnifiedCalendar.tsx lines 503-510 to derive
fallback totals with the event scheduling timezone, allocationAlgorithms.ts
lines 703-714 to calculate totalWeeks using the same timezone as slotsByWeek,
and SlotAllocationService.ts lines 1542-1547 to use timezone-aware week counting
for the server iteration bound.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 80bd2e8b-22d8-41dc-b49e-908092ebdd9d
📒 Files selected for processing (14)
__tests__/booking-algorithm/calendarUtils.test.ts__tests__/booking-algorithm/initial-allocation-guard.test.ts__tests__/booking-algorithm/mode-parity.test.ts__tests__/booking-algorithm/subscriptionValidation.test.tsapp/dashboard/consultant/[consultantId]/(features)/requests/RequestSlotAllocationTab.tsxapp/dashboard/consultant/[consultantId]/(features)/shared/components/UnifiedCalendar.tsxapp/dashboard/consultant/[consultantId]/(features)/shared/hooks/useSlotAllocation.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/allocationAlgorithms.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/allocationService.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/calendarUtils.tsapp/dashboard/consultant/[consultantId]/(features)/shared/utils/slotSelectionValidation.tsutils/slotAllocation/SlotAllocationService.tsutils/slotAllocation/SlotCalculationService.tsutils/slotAllocation/SlotValidationService.ts
…-aware session completeness The advisory-locked guard now re-checks idempotent replay after acquiring the event lock (all three modes), so a same-key double submit that lost the pre-transaction race replays the winner's batch instead of 409ing. Day completeness checks decompose each day into complete CONSECUTIVE sessions via countSessionsForDay — a bare length-modulo let disconnected fragments masquerade as complete sessions. Part of #998 review triage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|




Problem
The Allocate Slots dialog (RequestCalendar) is the booking surface for consultants and consultees, and its verdicts did not match the server's. Concretely:
getDay()mixed with UTC ISO keys,UnifiedCalendarused date-fnsstartOfWeek(browser-local), and only a few paths used the canonicalSlotCalculationService. The server bucketed by UTC Sundays for weekly limits but by server-localtoDateString()for per-day caps. For slots between 00:00 and 05:30 IST the calendar accepted selections the server rejected withWEEKLY_LIMIT/DAILY_LIMITerrors — and vice versa.Idempotency-Key(the [UMBRELLA] B2C state-machine and payments hardening — launch blockers + first-month #837 server replay path was dead code). Worse, auto-allocation locksauto-allocate:{consultantId}while manual allocation day-shards its lock key ([ALLOCATION] Narrow the consultant-level auto-allocate lock — now unblocked by the #440 exclusion constraint #860) — different Redis keys — so a consultant with the same request open in two tabs could run manual in one and auto in the other concurrently, and the manual path treated the already-allocated event as a legal re-allocation and silently deleted and replaced the winner's appointments. Group events (webinar/class) have no consultee lock at all.totalSessionsandpastConfirmedSlotCount, so it rejected valid in-progress reschedules that manual/auto accepted.callsPerWeek × 4 × durationInMonthsfallback assumed 4-week months — wrong for 28/29/30/31-day periods spanning 5–6 Sunday weeks, and moot anyway because the server throws for a subscription with no scheduling period.pendingToastslot), and wording drifted between the week view, month view, and requests table.Approach
ADR B9 — limits bucket by the event's scheduling timezone; display stays viewer-local. Every daily/weekly limit (subscription
callsPerWeekweeks, 1-session/day, 2-classes/day, consultation same-day) now buckets through two shared helpers,SlotCalculationService.dayKey(date, tz)andweekKey(date, tz), where the timezone is the event'sschedulingTimezonecolumn (defaultAsia/Kolkata). The keys are produced byIntlwith an explicit zone — nevertoDateString()or the process locale — so the client's interactive guards, the client auto-allocator, and the server validators (SlotValidationService,SubscriptionValidationService, the server auto-allocator) all agree on every machine. For the primary Indian market, "one session per day" now means exactly the calendar day users see on the grid. Rendering stays viewer-local by design (display and bucketing are different concerns);countWeeksperiod sizing deliberately stays UTC (shadowed by the authoritative plantotalSessions).ADR B10 — the
initialAllocationguard. The dialog sendsinitialAllocation: truefor freshPENDINGallocations (only whententativeSlotCount === 0); the server then rejects with a typed 409 if any confirmed (non-tentative) slot already exists — checked under the distributed locks and re-checked inside the write transaction on all three modes (manual/auto/requested). Reschedule and re-allocation flows omit the flag, preserving their replace semantics.Idempotency + 409 UX. Every client allocate path now sends an
Idempotency-Key(a retry of the identical payload reuses the key so the server replays the original batch; any payload change mints a fresh UUID). On 409 the dialog shows an "already allocated in another tab or by a teammate" toast, closes, and refreshes the request list; window focus also refetches so a stale tab self-heals.Requested-path parity. Client
preAllocateis renamedallocateRequestedSlots(matching the server'srequestedmode) and now passestotalSessionsand subtractspastConfirmedSlotCount, identical to manual/auto.Cleanups. Selection validators extracted from the 2,226-line hook into pure, unit-tested
slotSelectionValidation.ts(also the seed for the #997 Phase-3 server migration); all user-facing strings centralized inallocationMessages.ts; toast queue replaces the clobber-prone single slot; dead_-prefixed validators, the duplicated local-week grouper, and four copy-pasted fetch wrappers deleted; the 4-weeks/month fallback replaced by a disabled "plan configuration incomplete" row with a Sentry event; SentrycaptureExceptionadded to all client engine catch paths (subsystem: client,feature: slot-allocation, no PII).Testing
__tests__/booking-algorithm+__tests__/schedule), including six new suites:slot-boundary-bucketing(IST/UTC/DST boundary keys, client/server parity),required-slots-periods(28/29/30/31-day months, leap Feb 2028, 4/5/6-Sunday-week periods, callsPerWeek 1–7 × session durations 0.5–2h, totalSessions override, missing-period throw),mode-parity(auto output passes manual validation; requested honors totals/past counts; consecutive atoms at day boundaries),toast-queue,idempotency-key, andinitial-allocation-guard(409 with the flag, replace semantics preserved without it, tentative holds don't trip it).tsc --noEmitclean; eslint clean on all new files.Out of scope / follow-ups
useRequestedSlotsinteractive transaction split (bug(allocation): subscription Auto-Allocate fails with 500 'Unable to start a transaction in the given time' (~115s) — paid subscription left unallocated #908 pattern) is deferred.initialAllocation) can still re-enter the full-delete path; the fix needs an allocation precondition and is tagged onto the Request Calendar performance: slow PENDING list endpoints + move client-side allocation engine server-side #997 server-migration design.Part of #997.
🤖 Generated with Claude Code
Summary by CodeRabbit