CU-05: Event-type configuration → public booking-page enforcement
Priority: P0 Accounts/sessions: P1 host only (ravikantguptaofficial@gmail.com, signed into Calendo via Google, Gmail = host notification inbox). P3 (everythingaichannelemail@gmail.com) is used ONLY as a real guest email for the L3 guest-notification sub-section (m). No login as P3 is required. Parallel-safe: Yes. This suite only creates/edits/deletes its OWN, RUNID-scoped event types and bookings. It never edits global host availability, settings, or other suites' data. Exclusive (rewrites global host availability?): No. Do NOT touch the Availability tab. All limits are set per-event-type inside the event-type edit panel. Estimated time: ~75–90 minutes for one full run (14 sub-sections, each create + verify + cleanup). L3 reality checks: One — sub-section (n): the additional-guest invitee (P3) must receive a real "you're invited" email in their inbox. All other sub-sections are L1/L2 only.
Goal
This suite proves that every per-event-type setting a host configures in the Calendo dashboard is actually ENFORCED on the public booking page that invitees see and use. A scheduling product is only trustworthy if "I set a 15-minute slot interval / require a phone number / cap at 2 bookings a day / hide this event / allow group sign-ups" really changes what the invitee experiences. We create one uniquely-named event type per setting, configure it, then open the public booking page as an anonymous invitee and confirm the setting takes effect (duration shown, questions required, near-now slots hidden, secret event hidden from the list but bookable by direct link, group "spots left", prefilled fields, guest notification email actually delivered, etc.). It is the core "config → enforcement" contract of the product.
Preconditions
- The browser must already be logged in as P1 at https://calendo.dev/dashboard/ via a persisted Google session. Loading https://calendo.dev/dashboard/ must show the dashboard chrome (
#appLayout,#welcomeHeader) WITHOUT presenting a login screen.- If you land on
/auth/login.htmlor are prompted for a Google/Microsoft password, STOP. Do NOT attempt a cold login. Flag this as a precondition failure per00-setup-preconditions.mdand abort the suite.
- If you land on
- The host must have at least one active weekly availability window so the public booking page renders bookable slots in the current/next month. The 4 default event types ("15 Minute Chat", "30 Minute Meeting", "45 Minute Meeting", "60 Minute Deep Dive") and a default working-hours schedule are expected to exist. If the public booking page shows zero available days across 6 forward months for a freshly created event type, the host availability is empty — flag this as a precondition issue (do NOT edit availability to fix it; that is exclusive to availability suites) and mark affected sub-sections "blocked".
- For sub-section (n) only: P3's inbox (everythingaichannelemail@gmail.com) must be reachable in this browser (a Gmail tab signed into P3, OR you can confirm via P3 having forwarding) — see 00-setup-preconditions.md. If P3's inbox is not viewable in-browser, complete the booking (L1/L2) and move the email confirmation to Manual residue.
- Do NOT rely on the older Playwright selectors
#editEtModalorsummary:has-text("Limits"). The DEPLOYED dashboard uses a right-hand slide-in panel#editEtPanelwith collapsible section headers (.ep-section-header) titled "Limits & Buffers" and "Booking Questions". Advanced toggles (Secret / Group / Allow guests / Redirect / location address / price) live ONLY in the full create form inside the Event Types tab, NOT in the edit panel.
Test data
- RUNID: pick one fresh UTC token at the start, e.g.
20260601-1530. Use the SAME RUNID for every name in this run. - Naming convention — embed RUNID in every event-type name so the slug is unique and assertions can scope by RUNID. Calendo slugifies the name (lowercase, spaces→hyphens). Expected names/slugs:
- (a)
CU05 Duration ${RUNID}→ slugcu05-duration-${RUNID} - (b)
CU05 DescColor ${RUNID}→cu05-desccolor-${RUNID} - (c)
CU05 Location ${RUNID}→cu05-location-${RUNID} - (d)
CU05 Questions ${RUNID}→cu05-questions-${RUNID} - (e)
CU05 Conditional ${RUNID}→cu05-conditional-${RUNID} - (f)
CU05 Buffers ${RUNID}→cu05-buffers-${RUNID} - (g)
CU05 Caps ${RUNID}→cu05-caps-${RUNID} - (h)
CU05 Notice ${RUNID}→cu05-notice-${RUNID} - (i)
CU05 LockTz ${RUNID}→cu05-locktz-${RUNID} - (j)
CU05 Redirect ${RUNID}→cu05-redirect-${RUNID} - (k)
CU05 Secret ${RUNID}→cu05-secret-${RUNID} - (l)
CU05 Group ${RUNID}→cu05-group-${RUNID} - (m)
CU05 Prefill ${RUNID}→cu05-prefill-${RUNID} - (n)
CU05 Guests ${RUNID}→cu05-guests-${RUNID}
- (a)
- Invitee emails (plus-aliases of P1's inbox so all email lands in one searchable Gmail):
ravikantguptaofficial+inv-${RUNID}-<tag>@gmail.com, where<tag>is the sub-section letter (e.g.+inv-20260601-1530-d@gmail.com). Invitee name:Invitee ${RUNID} <tag>. - Additional guest email (sub-section n, L3):
everythingaichannelemail@gmail.com(P3 — a real separate inbox). - HOST_SLUG: read once at the start from the dashboard booking link (
#bookingLinkValue); call it<HOST_SLUG>.
Steps
0. Setup (run once)
- Action: Go to https://calendo.dev/dashboard/. Wait for the dashboard to load. Expect:
#appLayoutand#welcomeHeadervisible; no login screen. [L1] - Action: Read the host booking link text from the share box (
#bookingLinkValue). It looks likehttps://calendo.dev/booking/?user=<HOST_SLUG>. Record<HOST_SLUG>(everything afteruser=). Expect: A non-empty slug. [L1] Capture screenshot:cu05-00-dashboard-link. - Action: Click the Event Types sidebar tab (
.sidebar-nav a[data-tab="event-types"]). Expect: Panel#panel-event-typesbecomes active and shows the create form fields (#etName,#etDuration,#etLocation,#etSubmitBtn) and the existing event types list (#eventTypesList). [L1]
Order note: For each sub-section below, the pattern is the same. (1) CREATE the event type from the FULL form in the Event Types tab (this is the only form with Secret/Group/Guests/Redirect/location-address). (2) For settings the full form lacks (slot interval, buffers, min notice, max-per-day, locked timezone, custom questions, conditional questions), open the per-event slide-in EDIT panel (
#editEtPanel) on that event type and set them there, then Save. (3) Open the PUBLIC booking page in a way that simulates an anonymous invitee and verify enforcement.
Helper — opening the public booking page as an invitee: navigate to
https://calendo.dev/booking/?user=<HOST_SLUG>&event=<EVENT_SLUG>. The booking detail view is#booking-view; the event header is#sidebar-event-name. To pick a slot: click the first day cell with class.calendar-day.available, then click the first.time-slotbutton; if no available day appears, click the next-month nav button (.calendar-nav-btn, last one) and retry up to 6 times. The confirm form fields are#input-name,#input-email, optional#input-phone, custom questions inside#custom-questions, guests inside#guests-section; submit is#btn-confirm; success is the.confirmation-titlereading "Booking Confirmed!".
Helper — opening the EDIT panel for an event type: in the Event Types tab, find the event-type card whose title contains the RUNID name and click its "Edit" control. The slide-in panel
#editEtPanelgets classactive. Its sections are collapsible — click the section header text ("Limits & Buffers" or "Booking Questions") to expand. Field ids:#editEtSlotInterval,#editEtBufferBefore,#editEtBufferAfter,#editEtMinNotice,#editEtMaxPerDay,#editEtLockedTz, reminder checkboxes#editEtRemEmail24/1+#editEtRemSms24/1,#editEtReconfirmation, questions list#editEtQuestionsListwith+ Add questionbutton. Save with#editEtSaveBtn; the panel closes / removesactive.
(a) Duration + slot interval / granularity
- Action: In the Event Types tab create form, fill name
CU05 Duration ${RUNID}(#etName), select Duration = 30 min (#etDurationvalue30), leave Location = Google Meet, click Create (#etSubmitBtn). Expect: Form clears and the new card appears in#eventTypesListshowing the name and "30m". [L1] - Action: Open the edit panel for
CU05 Duration ${RUNID}. Expand "Limits & Buffers". Set Slot interval (#editEtSlotInterval) = 30 min. Save (#editEtSaveBtn). Expect: Panel closes. [L1] - Action: Reopen the edit panel, expand "Limits & Buffers". Expect:
#editEtSlotInterval=30and#editEtDuration=30(settings persisted). [L2] Close panel. - Action: Open the public booking page
…&event=cu05-duration-${RUNID}. Expect:#sidebar-event-nameshows the name;#sidebar-duration-textshows "30 min" (duration enforced). [L1] - Action: Click the first available day; inspect the listed time slots (
.time-slotbuttons in#time-slots-list). Expect: Consecutive slot start times are 30 minutes apart (e.g. 9:00, 9:30, 10:00 — NOT 9:15), confirming the 30-minute granularity. [L1] Capture screenshot:cu05-a-slots-30min. - Pass criterion (a): Sidebar shows 30 min duration AND visible slot starts are 30 minutes apart.
(b) Description + color
- Action: Create
CU05 DescColor ${RUNID}with Duration 30. In the create form set Description (#etDescription) =Color and description check ${RUNID}and pick a non-default color swatch in the color picker (#etColorSwatches; the hidden value lives in#etColor, default#2563ebblue — choose any other swatch). Click Create. Expect: Card appears; its color dot reflects the chosen color. [L1] - Action: Open the edit panel for it; confirm
#editEtDescholds the description text and the Color section preview shows the chosen color. Expect: Values persisted. [L2] Close panel. - Action: Open the public booking page
…&event=cu05-desccolor-${RUNID}. Expect:#sidebar-descriptionshows the description text; the page accent / event color matches the chosen swatch (header dot / brand accent). [L1] Capture screenshot:cu05-b-desc-color. - Pass criterion (b): Description text and chosen color both appear on the public booking page.
(c) Location config (video / in-person address) shown
- Action: Create
CU05 Location ${RUNID}with Duration 30. In the create form set Location (#etLocation) = "In person"; the detail input (#etLocationDetail→#etLocationValue) appears — fill it withSuite 200, 1 Market St, SF ${RUNID}. Click Create. Expect: Card created with In person location. [L1] - Action: Open the public booking page
…&event=cu05-location-${RUNID}. Expect:#sidebar-location-textshows the in-person addressSuite 200, 1 Market St, SF ${RUNID}(or "In person" with the address). [L1] Capture screenshot:cu05-c-location-inperson. - Action (video variant): Create a second event
CU05 LocationVideo ${RUNID}(slugcu05-locationvideo-${RUNID}) with Location = "Google Meet". Open its public page. Expect:#sidebar-location-textshows "Google Meet" (auto-generated video). [L1] - Pass criterion (c): In-person address text renders on the public page for the in-person event; "Google Meet" renders for the video event.
(d) Custom questions (text/select, required) render + required-validation blocks submit + answers saved [L2]
- Action: Create
CU05 Questions ${RUNID}(Duration 30, Allow guests can stay default). Then open its edit panel and expand "Booking Questions". Click "+ Add question" in#editEtQuestionsList. In the new row, set label =Company(placeholder "Question label"), keep type = text, and CHECK the required checkbox (input[type="checkbox"]in that row). Add a second question: label =Team size, change its type select to a dropdown/select option, add options (e.g.Small,Large), and CHECK required. Save (#editEtSaveBtn). Expect: Panel closes. [L1] - Action: Reopen the edit panel, expand "Booking Questions". Expect: Both questions present with correct labels, types, and required flags. [L2] Close panel.
- Action: Open the public booking page
…&event=cu05-questions-${RUNID}, pick a slot to reach the confirm form. Expect:#custom-questionsrenders both questions; the required ones carry a required marker. [L1] - Action: Fill
#input-name=Invitee ${RUNID} d,#input-email=ravikantguptaofficial+inv-${RUNID}-d@gmail.com, LEAVE the requiredCompanyquestion EMPTY, and click#btn-confirm. Expect: Submission is blocked — the empty required question field is focused / shows native validation (itscheckValidity()is false); no confirmation appears. [L1] Capture screenshot:cu05-d-required-block. - Action: Now fill
Company=Acme ${RUNID}and selectTeam size=Large, click#btn-confirm. Expect:.confirmation-titleshows "Booking Confirmed!". [L1] Capture screenshot:cu05-d-confirmed. - Action: Return to https://calendo.dev/dashboard/, open the Bookings tab (
a[data-tab="bookings"]→#bookingsTableContainer), find the booking for inviteeInvitee ${RUNID} d, open its detail. Expect: Detail shows a "Booking Questions" section listingCompany=Acme ${RUNID}andTeam size=Large(answers persisted). [L2] Capture screenshot:cu05-d-answers-saved. - Pass criterion (d): Required question blocks submit when empty; after filling, booking confirms; saved answers appear verbatim in the dashboard booking detail.
(e) Conditional questions show/hide based on prior answer
- Action: Create
CU05 Conditional ${RUNID}(Duration 30). Open its edit panel, expand "Booking Questions". Add question 1: label =Plan(or a Yes/No-style question). Add question 2: label =Budget, and configure its condition so it only shows when question 1's answer equals a specific value (e.g.Enterprise) — in the row's condition controls choose "show when [question 1] = Enterprise". Save. Expect: Panel closes; reopening shows both questions and the condition onBudget. [L2]
Note: the worker rejects forward-references / non-existent indices, so the condition MUST point to an earlier question. If the UI lets you save an invalid condition and the API errors, flag it.
- Action: Open the public page
…&event=cu05-conditional-${RUNID}, pick a slot to reach the form. In#custom-questions, set question 1 (Plan) to a NON-triggering value (e.g.Startup). Expect: TheBudgetquestion's form-group is hidden. [L1] - Action: Change question 1 to the triggering value
Enterprise. Expect: TheBudgetquestion becomes visible. [L1] Capture screenshot:cu05-e-conditional-shown. - Action: With
Budgetvisible and required-by-condition, leave it blank and click#btn-confirm. Expect: Submit blocked (Budget invalid). Then fillBudget=Over 50k, fill name/email (+inv-${RUNID}-e), confirm. Expect: "Booking Confirmed!". [L1] - Pass criterion (e): Budget hidden for non-triggering answer, shown (and validated) for the triggering answer; booking confirms once filled.
(f) Buffers before/after
- Action: Create
CU05 Buffers ${RUNID}(Duration 30). Open its edit panel, expand "Limits & Buffers". Set Buffer before (#editEtBufferBefore) = 30 and Buffer after (#editEtBufferAfter) = 30. Save. Reopen and confirm both values persisted = 30. Expect: Persisted. [L2] - Action: Create a baseline twin
CU05 BuffersBase ${RUNID}(Duration 30, buffers left at 0) for comparison. - Action: Open the public page for the baseline event, pick the first available day, and note the count of slots offered for that day. Then open the public page for
cu05-buffers-${RUNID}on the SAME day, and note the slot count. Expect: The buffered event shows FEWER (or equal-but-spaced-out) slots than the baseline on the same day, because the 30-min before/after buffers consume gaps between meetings. [L1] Capture screenshot:cu05-f-buffers-fewer-slots. - Pass criterion (f): Buffered event offers strictly fewer slots than the zero-buffer twin on the same available day (or visibly larger gaps between offered start times).
(g) Daily / weekly meeting caps (book up to the cap, confirm next is blocked)
- Action: Create
CU05 Caps ${RUNID}(Duration 30). Open its edit panel, "Limits & Buffers", set Max per day (#editEtMaxPerDay) = 1. Save; reopen to confirm#editEtMaxPerDay= 1. Expect: Persisted. [L2] - Action: Open the public page
…&event=cu05-caps-${RUNID}, pick the first available DAY, book one slot (name/email+inv-${RUNID}-g1). Expect: "Booking Confirmed!". [L1] - Action: Re-open the public page for the same event and navigate to the SAME day you just booked. Expect: That day now shows ZERO available slots (the day is full / not selectable / shows no
.time-slot), because the per-day cap of 1 is reached. Other days still show slots. [L1] Capture screenshot:cu05-g-day-capped. - Pass criterion (g): After 1 booking, the capped day offers no further slots while other days remain bookable.
Note on weekly caps: the dashboard edit panel exposes only per-day cap (
#editEtMaxPerDay); weekly/daily "meeting limits" are a schedule-level feature (availability schedulemeeting_limits), not a per-event-type field, so a true per-event WEEKLY cap is out of scope here — see TBD. Verify the daily cap above as the representative cap test.
(h) Minimum scheduling notice (near-now slots hidden)
- Action: Create
CU05 Notice ${RUNID}(Duration 30). Open its edit panel, "Limits & Buffers", set Min notice (hours) (#editEtMinNotice) = 72. Save; reopen to confirm = 72. Expect: Persisted. [L2] - Action: Open the public page
…&event=cu05-notice-${RUNID}. Expect: No slots are offered within the next 72 hours from now — today and the next ~3 days show no available.time-slots; the earliest selectable day is roughly 3+ days out. [L1] Capture screenshot:cu05-h-notice-hidden. - Action (control): Compare against any default event (e.g. "15 Minute Chat") on the public page, which should offer slots much sooner. Expect: The 72h-notice event's earliest slot is clearly later than the control's. [L1]
- Pass criterion (h): No bookable slot exists within 72 hours of "now" for the min-notice event; control event offers earlier slots.
(i) Timezone lock ("(locked)" shown on booking page)
- Action: Create
CU05 LockTz ${RUNID}(Duration 30). Open its edit panel, "Limits & Buffers", set Lock timezone (#editEtLockedTz) = New York (America/New_York). Save; reopen to confirm. Expect: Persisted. [L2] - Action: Open the public page
…&event=cu05-locktz-${RUNID}. Expect: The timezone selector (#timezone-select) is DISABLED, its value isAmerica/New_York, and the visible option text contains "(locked)" (e.g. "America/New York (locked)"). The invitee cannot change timezone. [L1] Capture screenshot:cu05-i-tz-locked. - Pass criterion (i):
#timezone-selectis disabled, fixed to America/New_York, and displays "(locked)".
(j) Post-booking redirect URL (invitee redirected with context params)
- Action: Create
CU05 Redirect ${RUNID}. In the create form, expand "Advanced" and set Redirect URL (#etRedirectUrl) =https://example.com/thanks-${RUNID}(must be http/https; the API rejects non-URLs and non-http schemes). Click Create. Expect: Card created. [L1] - Action: Open its edit/detail or re-open the create form on it to confirm the redirect URL persisted, OR proceed to behavioral check. [L2]
- Action: Open the public page
…&event=cu05-redirect-${RUNID}, pick a slot, fill nameInvitee ${RUNID} j/ email+inv-${RUNID}-j, click#btn-confirm. Expect: Instead of the in-app "Booking Confirmed!" screen, the browser navigates tohttps://example.com/thanks-${RUNID}?...with query params includinginvitee_name,invitee_email,event_type=cu05-redirect-${RUNID}, andstart_time=<booked ISO>. [L1] Capture screenshot:cu05-j-redirect-url(capture the redirected URL bar showing the params). - Pass criterion (j): After confirming, the invitee lands on the configured redirect URL with
invitee_name,invitee_email,event_type, andstart_timequery params populated.
(k) Secret event (hidden from public list, bookable via direct link, lock badge in dashboard)
- Action: Create
CU05 Secret ${RUNID}(Duration 30). In the create form CHECK "Secret" (#etSecretToggle). Click Create. Expect: Card created; in the dashboard event-types list it shows a secret/lock indicator (and is excluded from public listing). [L1] Capture screenshot:cu05-k-secret-dashboard. - Action: Open the public LIST page (no
event=param):https://calendo.dev/booking/?user=<HOST_SLUG>. Expect:#event-list-view/#event-types-gridlists the host's public events but does NOT containCU05 Secret ${RUNID}. [L1] - Action: Open the DIRECT link
…&event=cu05-secret-${RUNID}. Expect:#booking-viewopens and#sidebar-event-nameshowsCU05 Secret ${RUNID}— the secret event IS bookable via direct link. [L1] Optionally complete one booking (name/email+inv-${RUNID}-k) → "Booking Confirmed!". [L1] Capture screenshot:cu05-k-secret-direct. - Pass criterion (k): Secret event is absent from the public list but reachable and bookable via its direct
?event=link; dashboard shows it as secret.
(l) Group event (max attendees, "X spots left", multiple invitees can book)
- Action: Create
CU05 Group ${RUNID}(Duration 30). In the create form CHECK "Group event" (#etGroupToggle); the group fields appear (#etGroupFields) — set Max attendees per slot (#etGroupMax) = 3. Keep Allow guests as-is. Click Create. Expect: Card created; dashboard shows a "Group (max 3)" badge. [L1] Capture screenshot:cu05-l-group-dashboard. - Action: Open the public page
…&event=cu05-group-${RUNID}, pick a day. Expect: Slots render with a "spots" hint (e.g. "3 spots") next to slot times (group mode). [L1] - Action: Book the SAME slot once as invitee
+inv-${RUNID}-l1→ "Booking Confirmed!". Re-open the public page, navigate to the same day/slot. Expect: That slot is STILL available and now reads "2 spots left" (or "X spots left" with X reduced by 1). [L1] Capture screenshot:cu05-l-spots-left. - Action: Book the same slot again as
+inv-${RUNID}-l2→ "Booking Confirmed!". Re-open; the slot should now read "1 spot left". Book a third time as+inv-${RUNID}-l3. Expect: Third booking confirms (reaching max 3). Re-open the page on that day. Expect: The slot is now GONE/unavailable (max attendees reached). [L1] - Pass criterion (l): Slot accepts up to 3 distinct invitees, shows decreasing "X spots left" after each, and disappears once the cap of 3 is hit.
(m) Prefilled link ?name=&email= auto-fills the form
- Action: Create
CU05 Prefill ${RUNID}(Duration 30). [L1] - Action: Open the public page with prefill params:
https://calendo.dev/booking/?user=<HOST_SLUG>&event=cu05-prefill-${RUNID}&name=Pre%20Filled%20${RUNID}&email=ravikantguptaofficial%2Binv-${RUNID}-m%40gmail.com. Pick a slot to reach the confirm form. Expect:#input-nameis pre-populated withPre Filled ${RUNID}and#input-emailwithravikantguptaofficial+inv-${RUNID}-m@gmail.com, before any typing. [L1] Capture screenshot:cu05-m-prefilled. - Action: Click
#btn-confirmwithout editing. Expect: "Booking Confirmed!". [L1] - Pass criterion (m): Name and email fields auto-fill from the URL params; booking confirms with those values.
(n) Allow guests — add guest emails (P3) and L3-confirm the guest gets a notification email
- Action: Create
CU05 Guests ${RUNID}(Duration 30) with "Allow guests" (#etAllowGuestsToggle) CHECKED (it is checked by default). Click Create. Expect: Card created. [L1] - Action: Open the public page
…&event=cu05-guests-${RUNID}, pick a slot to reach the confirm form. Expect: The "Additional Guests" section (#guests-section) is VISIBLE with an "Add guest" button (#add-guest-btn). [L1] - Action: Click
#add-guest-btnonce; in the new guest input (.guest-email-input) entereverythingaichannelemail@gmail.com(P3). Fill#input-name=Invitee ${RUNID} n,#input-email=ravikantguptaofficial+inv-${RUNID}-n@gmail.com. Click#btn-confirm. Expect: "Booking Confirmed!". [L1] Capture screenshot:cu05-n-guest-confirmed. - Action: Go to the dashboard Bookings tab, open the booking for
Invitee ${RUNID} n. Expect: Detail shows the guesteverythingaichannelemail@gmail.comlisted (or the bookings list shows a "+1 guest" indicator). [L2] Capture screenshot:cu05-n-guest-in-detail. - Action (negative control): Create
CU05 NoGuests ${RUNID}with Allow guests UNCHECKED, open its public page, pick a slot. Expect:#guests-sectionis HIDDEN (no guest UI). [L1] - L3: See L3 reality checks below — confirm P3 actually received the guest invite email.
- Pass criterion (n): Guest section shows when allowed and hides when disallowed; the booking stores the guest; AND (L3) P3 receives a real guest-notification email.
L3 reality checks
Only sub-section (n) has an L3 check.
- Action: In the browser, open Gmail for P3 at https://mail.google.com (the inbox for everythingaichannelemail@gmail.com — it must already be the active/selected Gmail account per preconditions). In the Gmail search box, run the query:
subject:(invited) ${RUNID}and, if nothing, also tryfrom:(calendo) ${RUNID}and"CU05 Guests ${RUNID}". Expect: A recent email (within the last few minutes) whose subject indicates the recipient was invited to a meeting (the guest-notification email subject contains "invited"), and whose body references the eventCU05 Guests ${RUNID}(or "Meeting"), the host name (P1 / Ravi), and the inviteeInvitee ${RUNID} n, at the booked date/time. [L3] Capture screenshot:cu05-n-L3-guest-email. - Action: Open the email and verify the meeting date/time matches the slot you booked and that it is addressed to the guest (P3), not just the primary invitee. Expect: Details consistent with the booking. [L3]
Note: The PRIMARY invitee confirmation emails for all sub-sections land in P1's Gmail as plus-aliases (ravikantguptaofficial+inv-${RUNID}-*@gmail.com). Verifying those is OPTIONAL for this suite (this suite's only required L3 is the guest notification). If you want extra evidence, search P1's Gmail for inv-${RUNID} to see the batch of confirmations — but treat any missing primary-confirmation emails as Manual residue, not a suite failure, since email deliverability for the host inbox is covered by the notifications suite.
Cleanup
Delete EVERYTHING this run created so host accounts stay clean. Use the RUNID to find items.
- Bookings first: In the dashboard Bookings tab (
#bookingsTableContainer), for EACH booking whose invitee email containsinv-${RUNID}or whose event name containsCU05 … ${RUNID}(including the multiple group bookings l1/l2/l3 and all guest/prefill/redirect bookings), open it and Cancel it. Confirm each shows cancelled status. (Cancel bookings BEFORE deleting their event types so they don't dangle.) - Event types: In the Event Types tab, for EACH event type whose name contains
CU05and${RUNID}— that is (a) Duration, (b) DescColor, (c) Location, the LocationVideo twin, (d) Questions, (e) Conditional, (f) Buffers + BuffersBase twin, (g) Caps, (h) Notice, (i) LockTz, (j) Redirect, (k) Secret, (l) Group, (m) Prefill, (n) Guests + NoGuests twin — open its edit panel and click Delete (#editEtDeleteBtn), confirm in the dialog (#dialogConfirm). Expect: Each disappears from the list. Do NOT delete the 4 default event types. - Calendar side effects: Booking confirmations may create Google Calendar events on P1's connected calendar. After cancelling all bookings, open https://calendar.google.com as P1 and confirm no leftover events titled with
CU05 … ${RUNID}remain on the booked dates; delete any stragglers. (The redirect sub-section (j) and group sub-section (l) created real calendar events — verify those are gone after cancellation.) - Verify clean: Reload the Event Types tab and Bookings tab; searching/scanning for
${RUNID}should return nothing. The throwaway redirect target (example.com) requires no cleanup. No throwaway Calendo account was created (we used the persisted P1 session), so none to delete.
Pass/Fail criteria
The run PASSES only if ALL of the following hold:
- (a) Public page shows 30-min duration and slot starts spaced 30 minutes apart.
- (b) Description text and chosen non-default color both appear on the public page.
- (c) In-person address text renders on the public page for the in-person event; "Google Meet" renders for the video event.
- (d) Empty required custom question blocks submit; after filling, booking confirms; saved answers appear verbatim in the dashboard booking detail.
- (e) Conditional Budget question is hidden for the non-triggering answer and shown+validated for the triggering answer; booking confirms once filled.
- (f) The buffered event offers strictly fewer slots than its zero-buffer twin on the same available day.
- (g) After one booking on a max-per-day-1 event, that day offers no more slots while other days remain bookable.
- (h) No bookable slot exists within 72h of now for the 72h min-notice event; the control event offers earlier slots.
- (i)
#timezone-selectis disabled, fixed to America/New_York, and shows "(locked)". - (j) After confirming, the invitee is redirected to the configured URL with
invitee_name,invitee_email,event_type, andstart_timequery params. - (k) Secret event is hidden from the public list yet bookable via direct
?event=link; dashboard marks it secret. - (l) Group slot accepts up to 3 invitees with decreasing "X spots left" and disappears at the cap of 3.
- (m)
?name=and?email=auto-fill the confirm form and the booking confirms with those values. - (n) Guest section shows when allowed and hides when disallowed; the guest is stored on the booking; AND (L3) P3 actually receives the guest-notification email.
- Cleanup leaves no
${RUNID}event types or bookings, and no leftover Google Calendar events titled with${RUNID}.
The run FAILS if any sub-section's pass criterion is unmet, if any setting configured in the dashboard does NOT take effect on the public booking page, if the L3 guest email never arrives, or if a precondition (logged-in P1 session, host availability) is missing and was not properly flagged.
Evidence to capture
cu05-00-dashboard-link(HOST_SLUG source)cu05-a-slots-30min,cu05-b-desc-color,cu05-c-location-inpersoncu05-d-required-block,cu05-d-confirmed,cu05-d-answers-savedcu05-e-conditional-showncu05-f-buffers-fewer-slots,cu05-g-day-capped,cu05-h-notice-hiddencu05-i-tz-locked,cu05-j-redirect-urlcu05-k-secret-dashboard,cu05-k-secret-directcu05-l-group-dashboard,cu05-l-spots-leftcu05-m-prefilled,cu05-n-guest-confirmed,cu05-n-guest-in-detail,cu05-n-L3-guest-email- A written note recording: the RUNID used, HOST_SLUG, each created event-type slug, each booking's invitee email, and PASS/FAIL per sub-section (a)–(n) with the observed value (e.g. "h: earliest slot was 2026-06-04 09:00, > 72h — PASS").
Manual residue / cannot-verify
- Per-event WEEKLY cap: the dashboard edit panel only exposes a per-day cap (
#editEtMaxPerDay). True daily/weekly "meeting limits" are an availability-schedule feature, not a per-event-type field, so a per-event weekly cap cannot be configured/verified here — handed to the human / availability suite. - SMS reminders (sms_24h / sms_1h): the edit panel exposes SMS reminder checkboxes (
#editEtRemSms24/1), but actual SMS delivery cannot be confirmed in-browser (no phone inbox). Setting persistence can be verified [L2]; delivery is manual residue. - Reconfirmation emails: the
#editEtReconfirmationsetting persists [L2] but the time-delayed reconfirmation email send (24/48/72h before) cannot be observed within a single run window — handed to the human / a scheduled-job suite. - Primary-invitee confirmation email deliverability: verifying every plus-alias confirmation email in P1's Gmail is optional here and is owned by the notifications suite; missing host-side emails should be noted for the human rather than failing this suite.
- Google Calendar event creation specifics (attendee list, Meet link generation): this suite confirms cleanup of calendar events; deep verification of attendee fields and auto-generated Meet links on the host calendar is owned by the calendar-integration suite.
- Exact slot-count math under buffers: "fewer slots" is verified qualitatively by comparison to a twin; the precise expected count depends on the live host schedule and is not asserted to an exact number.