Context
Reschedule flows intentionally omit the initialAllocation guard introduced in #998 (they legitimately re-allocate), which leaves one residual race: a stale second tab submitting a full reschedule after the first tab completed it finds zero tentative slots, is classified as an initial allocation, and the manual path delete-and-recreates the winner's completed allocation (SlotAllocationService.ts:842-875, 2246-2299). The full-delete branch also lacks the imminent-slot protection the in-progress branch has. Partial-subscription stale tabs fail benignly on the exact-count check; consultations, webinars, and full reschedules are exposed.
Proposed approach
Add an allocation precondition for non-initial allocations — for example an expectedTentativeSlotCount or an updatedAt compare-and-set carried from the page that initiated the reschedule — so a stale tab mismatches and receives a conflict instead of replacing state. The natural place to build this is the #997 server-side allocation migration, which owns the request shape; this issue should ride that design rather than a standalone patch.
Audit id R2; found alongside #998. Part of the #997 design.
Context
Reschedule flows intentionally omit the
initialAllocationguard introduced in #998 (they legitimately re-allocate), which leaves one residual race: a stale second tab submitting a full reschedule after the first tab completed it finds zero tentative slots, is classified as an initial allocation, and the manual path delete-and-recreates the winner's completed allocation (SlotAllocationService.ts:842-875, 2246-2299). The full-delete branch also lacks the imminent-slot protection the in-progress branch has. Partial-subscription stale tabs fail benignly on the exact-count check; consultations, webinars, and full reschedules are exposed.Proposed approach
Add an allocation precondition for non-initial allocations — for example an
expectedTentativeSlotCountor anupdatedAtcompare-and-set carried from the page that initiated the reschedule — so a stale tab mismatches and receives a conflict instead of replacing state. The natural place to build this is the #997 server-side allocation migration, which owns the request shape; this issue should ride that design rather than a standalone patch.Audit id R2; found alongside #998. Part of the #997 design.