Skip to content

Manage Timings lets a consultant move a session the consultee already committed to, with no acceptance #1082

Description

@teetangh

A consultant can open Manage Timings on a consultation or subscription session that a consultee has already committed to, pick different times, and move the session — with no notice requirement and no acceptance from the other party. The consultee finds out when their calendar changes.

Why this happens

The MANAGE_TIMINGS picker policy sets minLeadHours: 0 and its own comment explains why: the surface has "no counterparty to give notice to". That is entirely true of the thing it was designed for — a consultant setting when their own webinar or class instance runs. It is false of a booked 1:1.

The menu does not make that distinction. ConsultantAppointmentsAdapter.tsx:212 offers the action for any appointment in a non-cancelled, non-past bucket:

if (appointment && vm.bucket !== "cancelled" && vm.bucket !== "past") {
  items.push({ key: "timings",});
}

So the policy is correct and the menu is offering it in the wrong place.

The rule

The deciding question is not who has authority over the calendar. It is whether anyone has already committed to a time.

Manage Timings — nobody has committed yet. The consultant is arranging their own schedule and no one else's diary is affected.

  • A webinar or class instance. The organiser sets when it runs and attendees buy into a published schedule; there is no one to negotiate with, and asking thirty attendees for permission is not a coherent flow.
  • An offering that has never been scheduled (the unscheduled-class-… / unscheduled-webinar-… synthetic ids).
  • A request whose slots are still tentative — nothing has been placed.

Reschedule — a counterparty holds a confirmed time. Moving it is a negotiation.

  • A consultation with allocated, non-tentative slots.
  • A subscription session with allocated, non-tentative slots.

No new mechanism is needed

The two-party protocol already exists and is already asymmetric in the right direction:

  • A consultee proposing a time inside the consultant's published availability auto-confirms, because publishing availability is standing consent to be booked within it.
  • A consultant proposing never auto-confirms, because a consultee merely being free at a time is not consent to be moved to it.
  • The initiator may withdraw; the recipient may decline; expiry and decline both drop the booking into the consultant's allocate queue, so nothing dead-ends.

Adding a separate "reschedule request" layer on top of proposals would duplicate this.

One round, deliberately. Propose, then accept or decline. A counter-round was specified but never built, and was removed in #1064. A second round doubles the state space to save a message that the decline path already handles.

No unilateral override

A consultant with a genuine emergency opens a proposal and the consultee accepts; if they never answer, expiry moves it to the allocate queue. Cancellation also remains available and refunds. There is therefore no case that requires a consultant to move a committed session without agreement, and adding one would create the shape that generates refund disputes — a consultee discovering a paid session moved with no say.

Scope

  • Gate the menu action by whether the booking has a committed counterparty, and offer Reschedule in its place for 1:1 bookings.
  • Gate the page too, not only the menu. The timings URL is linkable and survives a refresh, so the menu alone is not a control.
  • Group events keep Manage Timings unconditionally, including when their slots are confirmed.

Out of scope: any change to the proposal protocol itself, to the auto-confirm asymmetry, or to the number of rounds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions