Calendo Computer-Use Test Suite — Coverage Matrix
This document is the traceability matrix for the Calendo "Computer Use Test" suite: a set of browser-agent (computer-use) runbooks executed against production https://calendo.dev. It proves what is covered, at what verification tier, and lists every known gap honestly.
How to read this document
Verification tiers
| Tier | Meaning |
|---|---|
| L1 | UI-only — the agent observes the rendered page/state in the browser |
| L2 | Calendo persistence — state survives reload / is read back from Calendo's own backend (D1, API) |
| L3 | External reality — a real Google/Outlook calendar event and/or a real email, confirmed by opening Gmail/Calendar in the same browser |
Suite index (21 authored suites)
| Suite | Title | Pri | Accounts | Lane | Est (min) |
|---|---|---|---|---|---|
| CU-01 | Core booking lifecycle (book → reschedule → cancel) | P0 | P1 host + anon invitee | B | 30 |
| CU-02 | Auth lifecycle (register, verify, login, reset, delete) | P0 | fresh throwaway | D | 22 |
| CU-03 | Google Calendar integration (conflict, buffers, two-way) | P0 | P1 + Google Cal | D | 40 |
| CU-04 | Microsoft / Outlook calendar integration | P2 | Outlook acct | D | 35 |
| CU-05 | Event-type config → public booking-page enforcement | P0 | P1 host | B | 85 |
| CU-06 | Availability engine (weekly, overrides, holidays, slot-debug) | P0 | P1 host | X (exclusive) | 35 |
| CU-07 | Host-side booking management | P1 | P1 host | B | 40 |
| CU-08 | AI booking chatbot (public page) | P1 | anon invitee | B | 30 |
| CU-09 | AI dashboard assistant (feature parity) | P1 | P1 host | B | 45 |
| CU-10 | Landing + marketing + static pages + mobile | P1 | none (anon) | A | 15 |
| CU-11 | Public booking page UX (timezones, nav, QR, mobile) | P1 | anon | A/B | 22 |
| CU-12 | Routing forms (build → submit → route → analytics) | P2 | P1 + anon | B | 18 |
| CU-13 | Meeting polls (create → vote → tally → finalize) | P2 | P1 + anon | B | 18 |
| CU-14 | Team / org scheduling (roles, round-robin, collective) | P2 | P1 owner + P3 | D | 40 |
| CU-15 | Contacts, analytics dashboard, CSV export | P2 | P1 host | A | 25 |
| CU-16 | Settings & customization (profile, branding, BYOK, pixels) | P2 | P1 host | B | 30 |
| CU-17 | Slack notifications & outbound webhooks | P2 | P1 host | B | 30 |
| CU-18 | New-user onboarding wizard (4-step) | P2 | fresh throwaway | D | 22 |
| CU-19 | Embeddable booking widget (inline/popup/badge) | P3 | P1 + external page | B | 25 |
| CU-20 | Email sequences, reminders, reconfirmation (time-gated) | P3 | P1 host | B | 40 |
| CU-22 | Chrome extension for Gmail (manual-led) | P3 | P1 (manual) | manual | 20 |
Lanes / wave plan (see 00-setup-preconditions.md): Lane A = read-only (anytime); Lane B = host-writers using uniquely-named event types (parallel-safe); Lane D = account-isolated (fresh throwaway / teammate / Outlook). Wave 1 runs all A/B/D suites concurrently; Wave 2 runs CU-06 alone because it rewrites global host availability.
1. Feature-area → suite traceability matrix
Rows are capabilities aggregated from every suite's coverage_items, grouped logically. The Primary suite owns deep verification; Also touches suites exercise the area incidentally. The highest tier reached anywhere is shown.
1.1 Authentication, account & onboarding
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Email/password registration (happy path, verification gate) | CU-02 | CU-18 | L2 |
| Email verification email + link → account verified | CU-02 | CU-18 | L3 |
| Resend verification email | CU-02 | (CU-18 noted) | L2 |
Unverified-user dashboard gating → /auth/verify.html | CU-02 | CU-18 | L1 |
| Login happy path / wrong-password failure | CU-02 | — | L1/L2 |
| Forgot-password request + reset-password email + token flow | CU-02 | — | L3 |
| Old-password-rejected / new-password-accepted after reset | CU-02 | — | L2 |
| Account deletion (Settings → Danger Zone, double confirm) | CU-02 | CU-18 | L2 |
| Post-deletion login fails / dashboard inaccessible (401) | CU-02 | CU-18 | L2 |
| OAuth button presence (Google/Microsoft) on auth pages | CU-02 | CU-10 | L1 |
Standalone /onboarding/ calendar-connect page | CU-18 | — | L1 |
| In-dashboard 4-step wizard (Calendar/Schedule/Location/AI) | CU-18 | — | L1 |
Onboarding completion persists server-side (onboarding_completed=1) | CU-18 | — | L2 |
| Empty-availability schedule-setup nudge + dismissal persistence | CU-18 | — | L2 |
1.2 Booking lifecycle (invitee-driven)
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Anonymous invitee books a slot (name + email → Confirm) | CU-01 | CU-05, CU-08, CU-11, CU-19, CU-20 | L3 |
| Booking Confirmed page (event/duration/date/time/tz/host) | CU-01 | CU-11 | L1 |
| Confirmation page tokenized Reschedule/Cancel + add-to-calendar | CU-01 | CU-11 | L1 |
| Booking persists in dashboard Upcoming, survives reload | CU-01 | CU-07, CU-08, CU-20 | L2 |
Invitee self-serve reschedule via token (reschedule.html) | CU-01 | CU-07, CU-17 | L3 |
| Reschedule idempotency / already-rescheduled handling | CU-01 | — | L1 |
Invitee self-serve cancel via token (cancel.html + reason) | CU-01 | CU-16, CU-17 | L3 |
| Cancel idempotency / already-cancelled state | CU-01 | — | L1 |
| Confirmation / reschedule / cancellation emails (invitee + host) | CU-01 | CU-03, CU-20 | L3 |
| Test event-type cleanup (no stray calendar events) | CU-01 | — | L2 |
1.3 Calendar integration (Google & Outlook)
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Google Calendar shows Connected; persistence | CU-03 | — | L2 |
| Google one-time OAuth connect (incl. "unverified app" warning) | CU-03 | — | L1 |
| Outbound conflict blocking: real GCal BUSY removes overlapping slot | CU-03 | CU-06 (reason code) | L3 |
| Non-overlapping slots remain (targeted conflict, not outage) | CU-03 | — | L3 |
| Per-event-type before/after buffers suppress adjacent slots | CU-03 | CU-05, CU-06 | L3 |
Booking creates real GCal event <event> with <invitee> + attendees | CU-03 | CU-01, CU-07, CU-08, CU-14 | L3 |
| Reschedule moves the GCal event (old empty, new populated) | CU-03 | CU-01, CU-07 | L3 |
Cancel deletes the GCal event (sendUpdates=all) | CU-03 | CU-01, CU-07 | L3 |
| Inbound two-way sync: GCal-created event appears in Calendo Calendar tab | CU-03 | — | L2 |
| Google Meet conferenceData link attached (spot-check) | CU-03 | CU-05 | L1 |
| Outlook connection confirmed + persistence | CU-04 | — | L2 |
| Outlook OAuth connect (Microsoft consent, scopes, unverified warning) | CU-04 | — | L1 |
| Outlook BUSY event suppresses overlapping slot (Graph calendarView) | CU-04 | — | L3 |
| Outlook busy/tentative/oof = conflict; free/workingElsewhere = not | CU-04 | — | L3 |
| Deleting Outlook busy event restores slot (live, non-cached) | CU-04 | — | L3 |
| Booking writes real Outlook event + attendee | CU-04 | — | L3 |
| Cancel removes the Outlook event | CU-04 | — | L3 |
| Outlook primary-calendar dropdown lists the connection | CU-04 | — | L1 |
1.4 Event-type configuration & enforcement
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Event-type CRUD (overview + New flow, edit modal) | CU-05 | CU-01, CU-07, CU-09 | L2 |
| Duration + slot interval/granularity (30-min spacing) enforced | CU-05 | CU-11 | L1 |
| Description text rendered on public page | CU-05 | — | L1 |
| Event color (non-default swatch) reflected on public page | CU-05 | — | L1 |
| Location config (in-person address / Google Meet video) | CU-05 | — | L1 |
| Custom questions (text + select) render + required validation | CU-05 | — | L1 |
| Saved custom-question answers persisted, visible in booking detail | CU-05 | — | L2 |
| Conditional questions show/hide + conditional validation | CU-05 | — | L1 |
| Buffers before/after reduce offered slots vs zero-buffer twin | CU-05 | CU-03, CU-06 | L1 |
Per-day meeting cap (max_per_day=1) blocks further same-day slots | CU-05 | — | L1 |
| Minimum scheduling notice hides near-now slots (72h) | CU-05 | CU-06 | L1 |
| Timezone lock disables selector, shows "(locked)" | CU-05 | CU-11 (noted) | L1 |
| Post-booking redirect URL with invitee/event params | CU-05 | — | L1 |
Secret event (hidden from list, bookable via ?event=, badge) | CU-05 | — | L1/L2 |
| Group event (max attendees, "X spots left", cap enforced) | CU-05 | — | L1 |
Prefilled booking link ?name=&email= auto-fills form | CU-05 | — | L1 |
| Allow-guests toggle (section shown/hidden, guest stored) | CU-05 | CU-07 | L2 |
| Guest-notification email to P3 inbox | CU-05 | CU-07 | L3 |
| Edit-panel setting persistence across reopen | CU-05 | CU-09 | L2 |
1.5 Availability engine
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Weekly recurring schedule (Mon–Fri 09:00–17:00 = 40.0 hrs) + persistence | CU-06 | — | L2 |
| Public page offers only scheduled weekdays; weekends unavailable | CU-06 | CU-11 | L1 |
| Date override that BLOCKS a weekday zeroes that day's slots | CU-06 | — | L1 |
| Date override that OPENS a normally-off Saturday surfaces slots | CU-06 | — | L1 |
| Holiday preset (US 2026) auto-blocks an upcoming holiday | CU-06 | — | L1 |
| Holiday renders blocked in override mini-calendar (tooltip) | CU-06 | — | L1 |
| Per-event buffers (30/30) + min-notice (48h) reduce slots vs default | CU-06 | CU-05 | L1 |
| Multiple named schedules drive different event types independently | CU-06 | CU-09 | L2 |
| Schedule-level daily meeting limit persists | CU-06 | — | L2 |
slot-debug endpoint returns available + reasons[] | CU-06 | — | L2 |
slot-debug reason codes (no_schedule, outside_hours, date_override, holiday, min_notice, max_future) | CU-06 | — | L2 |
| Create/select/delete non-default schedule; default protected | CU-06 | CU-09 | L2 |
| Baseline capture + full restoration of global schedule | CU-06 | — | L2 |
1.6 Host-side booking management
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
Book-on-behalf from dashboard (/api/book-on-behalf) | CU-07 | CU-15 (seeding) | L3 |
| Bookings filters (Upcoming/Past/Cancelled; no_show exclusion) | CU-07 | CU-15 | L1 |
| Meeting search by invitee name | CU-07 | — | L1 |
| Booking detail sidebar (status/title/datetime/invitee/location/timeline) | CU-07 | — | L1 |
| Mark past booking as no-show | CU-07 | CU-09, CU-15 | L2 |
| No-show reflected in Analytics No-Show Rate | CU-07 | CU-09, CU-15 | L2 |
| Add internal note via sidebar, persists across reload | CU-07 | CU-09 | L2 |
| Attach a guest at booking time; shown in host detail | CU-07 | CU-05 | L3 |
| Cancel from dashboard sidebar → Cancelled filter + badge | CU-07 | CU-01 | L3 |
| Reschedule via token link (no host-side reschedule button exists) | CU-07 | CU-01 | L3 |
1.7 AI features (the differentiator)
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Public-page AI chat surface presence (finding: hidden in prod) | CU-08 | CU-11 (noted) | L1 |
Conversational NL request → AI reply with real slots (/api/ai/chat) | CU-08 | — | L1 |
| AI latency vs ~2s target (measured, not certified) | CU-08 | — | L1 |
| AI proposes only real slots (no hallucinated times) | CU-08 | — | L1 |
| Conversational slot pick → inline booking form → real booking | CU-08 | — | L3 |
| AI-chat booking appears in dashboard with correct details | CU-08 | — | L2 |
| Ambiguity handling ("next Tuesday") + impossible-request decline | CU-08 | — | L1 |
| Scope enforcement (off-topic refused) in public chat | CU-08 | CU-09 | L1 |
| Grid fallback completes booking independently; AI⊆grid slot set | CU-08 | CU-11 | L1 |
| 429/529 rate-limit static fallback recognized | CU-08 | — | L1 |
Dashboard AI panel open (#aiPanel, mobile FAB) | CU-09 | CU-16 | L1 |
get_event_types / get_bookings / get_analytics (read tools) | CU-09 | — | L1 |
create_event_type / update_event_type via AI + reload verify | CU-09 | — | L2 |
get_booking_link + copy_to_clipboard | CU-09 | — | L1 |
add_booking_notes / mark_no_show via AI | CU-09 | CU-07 | L2 |
create_availability_schedule / delete_availability_schedule | CU-09 | CU-06 | L2 |
get_embed_code (inline + popup snippets) | CU-09 | CU-19 | L1 |
navigate_to (limited tab enum) | CU-09 | — | L1 |
get_audit_log (AI writes are audit-logged) | CU-09 | CU-14 | L2 |
manage_tracking (get) / manage_slack (get) read-only probes | CU-09 | CU-16, CU-17 | L1 |
delete_event_type with confirm guardrail | CU-09 | — | L2 |
| Off-topic guardrail refusal | CU-09 | CU-08 | L1 |
| Feature-parity gap detection (polls have no AI tool) | CU-09 | CU-13 | L1 |
| False-success detection (tool claims success w/o state change) | CU-09 | — | L2 |
| BYOK key applied to assistant (inferred via fake-key auth failure) | CU-16 | CU-09 | L1 |
| Welcome message set via AI assistant → public page | CU-16 | — | L1 |
1.8 Public booking page UX & marketing/static pages
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Timezone picker shifts displayed slot times + "Times in …" label | CU-11 | CU-05 (lock) | L1 |
| Locked-timezone behavior (disabled selector) noted | CU-11 | CU-05 | L1 |
| Calendar month next/prev nav; prev disabled on current month | CU-11 | CU-01 | L1 |
| Day selection reveals time-slots panel; unavailable greyed; today marker | CU-11 | CU-01, CU-06 | L1 |
| Empty-availability handling ("No available times", not blank) | CU-11 | — | L1 |
Event-list rendering (.event-card) | CU-11 | CU-14 (team page) | L1 |
Brand color applied via applyBranding() (--brand) | CU-11 | CU-16 | L1 |
| QR code render client-side (booking-link + per-event) + PNG download | CU-11 | — | L1 |
| Correction: confirmation page has NO QR (only calendar/manage links) | CU-11 | — | L1 |
| Mobile layout @375px (sidebar collapse, stacking, no overflow) | CU-11 | CU-10 | L1 |
| Happy-path booking → "Booking Confirmed!" + add-to-calendar/manage | CU-11 | CU-01 | L1 |
| Landing loads anon (no logged-out redirect to dashboard) | CU-10 | — | L1 |
| Hero AI messaging headline + subtitle + CTAs | CU-10 | — | L1 |
| Six feature cards with correct titles | CU-10 | — | L1 |
| How It Works (3 steps) | CU-10 | — | L1 |
| Pricing (Free $0 "Most Popular" + Pro $2/mo) cards + CTAs | CU-10 | — | L1 |
| "Why it's free" section + CTA | CU-10 | — | L1 |
Header nav anchors smooth-scroll; Docs link → /docs/ | CU-10 | — | L1 |
| Docs interactivity (expand/collapse, sidebar anchor, embed guide) | CU-10 | CU-19 | L1 |
| Footer 5 links resolve (Docs/Login/Signup/Privacy/Terms) | CU-10 | — | L1 |
| Privacy + Terms pages render with expected headings/dates | CU-10 | — | L1 |
Clean URLs and .html forms both resolve | CU-10 | — | L1 |
| Login + Register pages render forms + OAuth buttons | CU-10 | CU-02 | L1 |
| Console free of JS/asset errors (desktop + mobile) | CU-10 | — | L1 |
| Mobile @375px: hamburger, drawer, no overflow, single-column stack | CU-10 | — | L1 |
1.9 Routing forms & meeting polls
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Create routing form (name, slug, fields, rules) | CU-12 | — | L2 |
| Conditional routing rules (first-match-wins ordering) | CU-12 | — | L2 |
| Form card shows field/rule counts + Active badge; persists | CU-12 | CU-15 (surface) | L2 |
| Public routing form loads anon; renders fields | CU-12 | — | L1 |
| Answer set A → route to event type A; set B → route to B | CU-12 | — | L1 |
| Required-field validation on public form | CU-12 | — | L1 |
| Routing analytics submission count increments | CU-12 | CU-15 | L2 |
| Routing analytics conversion (0 because no booking) + per-ET breakdown | CU-12 | CU-15 | L2 |
| Create meeting poll (title, desc, 3+ options); persists + "0 voters" | CU-13 | CU-15 (surface) | L2 |
Resolve poll ID; correct public URL /poll/?id= (vs broken Copy Link) | CU-13 | — | L1 |
| Anonymous yes/maybe/no votes; multiple voter columns | CU-13 | — | L1 |
| Votes persist across reload; voter_count increments 0→2 | CU-13 | — | L2 |
| Per-option tally + auto-computed "Best option" | CU-13 | — | L1 |
| Finalize poll → "finalized" badge + "Meeting confirmed!" + winner | CU-13 | — | L2 |
GET /api/polls/<ID> confirms finalized status + winning option | CU-13 | — | L2 |
1.10 Team / org scheduling
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Create org as owner (auto slug); owner controls visible | CU-14 | — | L1 |
| Invite existing user (P3) → added immediately; persists | CU-14 | — | L2 |
| Role management (promote/demote); owner-only controls | CU-14 | — | L1 |
| Role constrains capability (admin vs member gating) | CU-14 | — | L1 |
| Round-robin team event type; union availability | CU-14 | — | L1 |
Round-robin assignment rotates / least-booked (assigned_user_id) | CU-14 | — | L2 |
| Collective team event type; intersection slot logic | CU-14 | — | L1 |
Public team page /team/<slug> lists org/members/event types | CU-14 | CU-11 | L1 |
| Per-user audit/activity log loads + filters (event_type.created, booking.created) | CU-14 | CU-09 | L2 |
| Team booking → invitee/host emails + GCal events | CU-14 | CU-03 | L3 |
1.11 Contacts, analytics & export
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Contacts aggregate invitees (one row per unique email) | CU-15 | — | L2 |
| Contacts columns (Name/Email/Phone/Last/Next/Meetings) | CU-15 | — | L1 |
| Contacts search (name + email) | CU-15 | — | L1 |
| Contacts filters (All / New 30d / No upcoming) | CU-15 | — | L1 |
| Analytics headline stats (Total/ThisMonth/Cancel/No-Show/Popular) | CU-15 | CU-07, CU-09 | L2 |
| 30-day Booking Volume bar chart | CU-15 | — | L1 |
| Event Type Breakdown table (per-ET bookings/cancel/no-show) | CU-15 | CU-09 | L1 |
Quirk: #exportRange scopes CSV only, not on-screen numbers | CU-15 | — | L1 |
CSV export calendo-bookings-<date>.csv — exactly 15 columns in order | CU-15 | — | L2 |
| CSV escapes commas/quotes; range param genuinely scopes export | CU-15 | — | L2 |
1.12 Settings, customization & integrations
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Profile display name persists + renders on public page | CU-16 | — | L2 |
| Gap: no timezone field in profile (edited on schedule instead) | CU-16 | CU-06 | L1 |
| Cancellation policy persists + shows on confirmation/cancel pages | CU-16 | CU-01 | L1/L2 |
Brand color (#ff5500) persists + restyles public page (--brand) | CU-16 | CU-11 | L1 |
Logo URL persists + renders as img.host-avatar | CU-16 | — | L1 |
Email blocklist (exact + @domain) rejects at /api/book (403) | CU-16 | — | L2 |
| BYOK Anthropic key save/active/remove; never echoes secret; persists | CU-16 | CU-09 | L2 |
| GA Measurement ID + Meta Pixel ID injected at runtime into public head | CU-16 | — | L1/L2 |
Welcome message via AI → #host-welcome on public page | CU-16 | — | L1 |
Register outbound webhook (POST /api/webhooks, 201 + secret) | CU-17 | — | L2 |
| List webhooks (persistence) | CU-17 | — | L2 |
booking.created webhook received (headers + signed body) | CU-17 | — | L3 |
booking.cancelled webhook (cancelled_by:host) | CU-17 | — | L3 |
booking.rescheduled webhook (previous_* + changed time) | CU-17 | — | L3 |
| Slack incoming-webhook save validation + Connected + Test round-trip | CU-17 | — | L3 |
Slack booking.created formatted message (when real Slack available) | CU-17 | — | L3 |
Webhook deletion (DELETE /api/webhooks/:id) | CU-17 | — | L2 |
1.13 Embeds, email sequences & extension
| Capability | Primary suite | Also touches | Top tier |
|---|---|---|---|
| Dashboard generates 3 embed snippets (inline/popup/badge) | CU-19 | CU-09 (get_embed_code) | L1 |
| Two distinct embed scripts serve as JS (not 404/HTML) | CU-19 | — | L2 |
Inline iframe render with embed=1 chrome stripping (foreign origin) | CU-19 | — | L1 |
| Popup modal overlay iframe (close via x/Esc/backdrop) | CU-19 | — | L1 |
| Floating badge pill → modal iframe | CU-19 | — | L1 |
Iframable from non-calendo origin (no X-Frame-Options: DENY) | CU-19 | — | L1 |
Cross-origin script execution (CORS *) | CU-19 | — | L1 |
| Full booking completed inside embedded iframe | CU-19 | — | L2 |
calendo:booking-confirmed postMessage re-dispatched to host window | CU-19 | — | L1 |
| In-embed booking cleanup (cancel) | CU-19 | — | L2 |
| Create email sequence (trigger/delay/subject/body) + persistence | CU-20 | — | L2 |
| Template variable substitution in delivered sequence emails | CU-20 | — | L3 |
| Immediate booking-confirmation email content (subject/links) | CU-20 | CU-01 | L3 |
| Host notification email content | CU-20 | CU-01 | L3 |
| Cron-driven sequence engine (after_booking delay-0 window) | CU-20 | — | L3 |
| Reminder config (24h/1h) + reconfirmation config (24/48/72) persist | CU-20 | CU-05 | L2 |
| Chrome MV3 extension loads (name/version/icons) | CU-22 | — | L1 (manual) |
| Popup link validation + save (chrome.storage.sync) + copy | CU-22 | — | L1 (manual) |
| Gmail content-script button injection + link insertion at cursor | CU-22 | — | L1 (manual) |
| Inserted link resolves to live public booking page | CU-22 | — | L2 |
2. Automation status
2.1 Fully automated (agent completes end-to-end in-browser, including L3 where claimed)
These suites/areas are driven to completion by the computer-use agent with no required human step inside the run (transient retries excepted):
- CU-01 — Core booking lifecycle, including real GCal create/move/delete and Gmail email checks.
- CU-02 — Auth lifecycle, including clicking real verification + password-reset links from Gmail.
- CU-03 — Google Calendar conflict/buffer/two-way sync, including L3 calendar + Gmail evidence.
- CU-05 — Event-type config → public-page enforcement (L1/L2 across all settings + L3 guest email).
- CU-06 — Availability engine (L1/L2), run alone in Wave 2; fully self-restoring.
- CU-07 — Host-side booking management (book-on-behalf, no-show, notes, guest, cancel/reschedule) with L3.
- CU-09 — AI dashboard assistant feature-parity actions (read + write tools, reload-verified).
- CU-10 — Landing/marketing/static pages + mobile (anonymous, read-only, L1).
- CU-11 — Public booking page UX (timezones, nav, empty-state, QR render, mobile, one booking).
- CU-12 — Routing forms build → submit → route → analytics (L1/L2).
- CU-13 — Meeting polls create → vote → tally → finalize (L1/L2).
- CU-15 — Contacts, analytics, CSV export (L1/L2, including CSV column/escape verification).
- CU-16 — Settings & customization (profile, policy, brand, logo, blocklist, BYOK, GA/Meta pixels).
- CU-17 — Outbound webhooks via webhook.site receipt + Slack Test round-trip (L3 where Slack available).
- CU-19 — Embeddable widget (inline/popup/badge) on a foreign-origin page, with in-embed booking.
Note on CU-08 (AI booking chatbot): the suite is fully runnable, but its headline finding is that the public AI chat is intentionally hidden in production (inline
#ai-chat-promptisdisplay:noneand the floatingchat-widget.jsbubble is not imported). The agent verifies/api/ai/chatbehavior directly and books via the conversational form, but the differentiator is "dark" in the live UI — a product decision, not a test failure.
2.2 Partially automated — has manual residue
These suites run but leave specific items a human must confirm out-of-band. Source: each suite's manual_residue.
| Suite | Manual residue (must be confirmed by a human) |
|---|---|
| CU-01 | Email deliverability/spam placement & non-Gmail rendering; .ics DTSTART/DTEND contents (agent can't parse); attendee-side RSVP delivery is ambiguous (invitee is a plus-alias of the host's own Gmail); whether GCal is truly two-way vs one-way write. |
| CU-02 | In-dashboard verification banner unreachable in normal flow (dead code?); second delete dialog says "type your email" but offers no input; anti-enumeration forgot-password path only unit-tested; token expiry/reuse only unit-tested; can't confirm D1 rows purged on delete; OAuth flows not exercised. |
| CU-03 | Webhook-driven inbound auto-cancel (delete GCal event → Calendo auto-cancel) non-deterministic in-browser; freeBusy/push latency may need retries; whether the "unverified app" warning still shows depends on Google status; watch-channel renewal cron unobservable. |
| CU-04 | Whole suite is residue if the Microsoft/outlook.com session needs a mid-run password (no cold login); publisher-verification warning documented only; token-refresh/offline_access lifecycle can't be force-triggered; reminder/organizer semantics not asserted; email L3 residue if P1 Gmail not logged in. |
| CU-05 | Per-event WEEKLY cap not settable in edit panel; SMS reminder delivery unverifiable; reconfirmation emails outside run window; primary-invitee email deliverability owned by notifications suite; deep GCal attendee/Meet verification owned by CU-03; buffered slot count verified qualitatively only. |
| CU-06 | slot-debug reasons google_calendar / outlook_calendar need a connected conflicting calendar (deferred); booking_conflict / event-type daily_cap may be unexercised in a clean run (unit-tested); full meeting-limit emptying is unit-tested; DST-boundary correctness is unit-tested. |
| CU-07 | No host-side dashboard Reschedule button (only token link); no API to add a guest to an existing booking; dashboard shows no-show rate not raw count; verifying the P3 guest email needs that inbox open; email timing depends on Resend; past-start book-on-behalf behavior needs human confirm. |
| CU-08 | Product decision to actually expose AI chat (currently hidden); sub-2s SLA over time; 429/529 + Workers-AI llama-3.3 fallback quality (external); cross-timezone label correctness; chat session isolation across invitees (localStorage leakage). |
| CU-09 | Embed snippet rendering on a real external page; no create_poll AI tool (parity gap to fix); no un-mark for no-show (human must restore real bookings); high-risk tools (delete_account, upgrade_to_pro, manage_paypal/slack set, trigger_password_reset, resend_verification, submit_feedback, update_settings) skipped on prod; can't independently verify the model self-ID claim. |
| CU-10 | Subjective visual/aesthetic quality; SEO/meta/OG/favicon correctness; real OAuth consent flows; cross-browser + real-device rendering; whether /docs (no slash) 404s while /docs/ works. |
| CU-11 | Empty event-list state can't be triggered on P1 without deleting all event types; whether the downloaded QR PNG actually scans to the right URL; the exact intended P1 brand color; pixel-perfect mobile ergonomics; L3 reality for the Section G booking owned by CU-01/02. |
| CU-12 | Conversion attribution (booked count / %) not verified (no confirmed booking); "No matching event type" 404 path not exercised; contains operator + multi-condition AND rules not covered; inactive-form 404 not covered; OS clipboard read not relied upon. |
| CU-13 | No in-UI poll delete (D1 cleanup if needed); finalize produces no external artifact (no event/email) — confirm intended; defect: dashboard Copy Link copies broken /booking/?poll=; defect: dashboard polls-list Finalize button POSTs with no body and is rejected; deadline expiry untestable (no deadline field). |
| CU-14 | Whether the round-robin assigned member actually got the GCal event/email can't be confirmed in-browser (side-effects route to booking-page owner P1); server-side 403 role enforcement only UI-verified; no delete control for org/team event types (D1 cleanup); org-level actions not written to audit log (possible gap); round-robin rotation non-deterministic. |
| CU-15 | Contacts have no in-UI delete (RUNID rows persist); no-show-rate correctness needs real no-show data; routing/poll math not exercised end-to-end here; precise 90d/1y CSV cutoffs need bookings older than the windows. |
| CU-16 | Can't prove the BYOK key is actually used for a billed call (only inferred from fake-key failure); profile timezone change propagation owned elsewhere; welcome-message editing has no dashboard input (AI/API only); encryption-at-rest of the key can't be observed in-browser; real GA/Meta ingestion out of scope. |
| CU-17 | HMAC X-Calendo-Signature validity can't be recomputed in-browser (verify one out-of-band); real Slack channel rendering needs a real workspace; whether clearing a test Slack URL is safe depends on P1 usage; supporting Gmail emails are the email path, not the webhook path. |
| CU-18 | Full click-through of wizard steps 2→4 needs a human with a pre-consented disposable Google account (Step 1 has no skip); the "OK" branch of the schedule-setup prompt only code-inspected; verification-email deliverability depends on Resend; resend-verification flow not exercised; wizard location → event-type persistence needs the blocked hand-driven path. |
| CU-19 | Creating a true foreign-origin host page depends on agent browser capability (else human pastes snippets on a real site); inspecting the postMessage/CustomEvent needs JS injection in host context; exact response headers (CORS, no X-Frame-Options) need network-panel/curl; optional downstream email/GCal owned by other suites. |
| CU-20 | Reminder timing (24h/1h) can't be confirmed in a short run (note quirk subject "in 1 hours"); reconfirmation delivery + Confirm/Cancel-Attendance clicks; after_booking delay-0 email may need a later Gmail re-check (cron lag); before/after_meeting trigger types configured-but-not-delivery-verified; SMS out of scope; Resend dashboard not openable. |
| CU-22 | Loading the unpacked MV3 extension via chrome://extensions (agent can't); driving the real Gmail compose DOM (obfuscated selectors); cross-device chrome.storage.sync propagation (needs a 2nd signed-in Chrome); cloud-sync latency/quota; manual extension removal + storage cleanup. |
2.3 Out of scope / TBD
A. Global out-of-scope (no test mode / not feasible for a browser agent) — never silently dropped
These are explicitly excluded across the whole suite and require separate manual/human handling:
| Area | Why excluded |
|---|---|
| Stripe payments (paid bookings, holds, refunds) | Live mode only, no Stripe test mode in production. |
| PayPal | Live integration, no safe test path. |
| Coupons at checkout | Tied to the paid-booking flow (above). |
| Pro-upgrade flow | Real billing; not exercised on the production account. |
| All Pro-gated features | Includes SMS/Twilio reminders (also need a real phone), custom domains, and remove-branding. Setting persistence is sometimes checked, but delivery/effect is not. |
| Admin panel | Gated to a different hardcoded email; not accessible to P1. |
These are intentionally listed, not dropped. If/when Stripe test mode, a phone inbox, or an admin account become available, dedicated suites should be authored: paid-booking lifecycle, coupon enforcement, Pro-upgrade, SMS reminders, custom-domain, and admin-panel.
B. Adjacent capabilities with no authored suite
No suite currently covers (treat as TBD / future work):
- Native mobile apps — none exist; only responsive web (@375px) is tested (CU-10/11).
- CRM integrations / SSO (SAML) / Zapier / generic third-party automation — no suites; only the generic outbound-webhook + Slack paths (CU-17) and the Chrome extension (CU-22) exist as integration coverage.
C. Per-suite TBD items (deferred to future or separate suites)
| Suite | Deferred (tbd_items) |
|---|---|
| CU-01 | Reminder emails (time-based); cross-timezone slot correctness; recurring booking lifecycle; paid/Stripe-held lifecycle; Outlook parity for the lifecycle; host-initiated dashboard cancel/reschedule. |
| CU-02 | Full OAuth register/login (Google + Microsoft); browser-verified session-invalidation-on-reset; deep server-side data-deletion audit; rate-limiting on repeated attempts. |
| CU-03 | Outlook conflict + two-way sync (→ CU-04); multiple/non-primary Google calendars; Google Meet conferenceData depth; behavior when GOOGLE_CLIENT_ID unset / refresh fails (unit-tested). |
| CU-04 | Teams OnlineMeetings join-link verification; multi-Outlook-account aggregation; buffer × Outlook conflict interaction; Outlook events in dashboard Calendar tab. |
| CU-05 | Per-event weekly/daily meeting-limit caps; SMS reminder E2E; reconfirmation scheduled-send; paid/coupon enforcement; recurrence options; round-robin/collective (→ CU-14). |
| CU-06 | L3 external reality (out of scope for availability-only); team/collective slot computation; onboarding-wizard availability path; API validation error paths (unit-tested). |
| CU-07 | Recurring-booking cancel scopes; reconfirmation status surfacing; merged external calendar events in list; paid-booking hold/cancel + webhook delivery; AI-assistant parity for host ops (→ CU-09). |
| CU-08 | Dedicated timezone-conversion suite for AI slots; floating chat-widget.js bubble (once wired); formal /api/ai/chat latency benchmarking; Outlook L3 for AI-chat booking. |
| CU-09 | No create_poll/meeting-poll AI tool (parity gap); navigate_to can't reach calendar/contacts/event-types tabs; high-risk billing/auth/integration tools deferred to throwaway account; embed render on external site. |
| CU-10 | Register form submission; login/OAuth completion; Pro "Upgrade" destination (auth-gated); unlinked docs sub-pages; server-side HTTP status assertion. |
| CU-11 | Whether a reserved always-empty event exists in prod; locked-timezone event coverage (needs fixture); AI inline chat on booking page (→ AI suites). |
| CU-12 | E2E conversion tracking; editing an existing routing form (PUT); slug-collision 409; contains + multi-condition AND; no-match 404 path. |
| CU-13 | Voting-deadline enforcement (no UI field); whether finalize should create a booking/event/email; poll edit/delete UI; poll votes in main Analytics. |
| CU-14 | Email-based pending-invitation acceptance; booking via P3's own slug for member-scoped L3; org/team-event-type deletion (API/D1); per-member round-robin tuning; collective multi-attendee invites. |
| CU-15 | E2E routing conversion (→ CU-12); E2E poll voting/finalize (→ CU-13); no-show lifecycle (→ CU-07); JSON export variant of analytics export. |
| CU-16 | Real GA/Meta ingestion; E2E BYOK with a billed key; profile timezone propagation; Outlook-specific settings. |
| CU-17 | Webhook retry/backoff + auto-disable after 5 failures; UTM propagation in payload; PUT /api/webhooks/:id update flows. |
| CU-18 | Whether standalone /onboarding/ and the 4-step wizard should unify (product Q); OAuth-signup onboarding (auto-verifies); mobile wizard rendering; mid-wizard calendar-connect resume logic. |
| CU-19 | data-calendo-event/-color/-text customization (documented but not emitted by generator); badge color/text E2E; mobile/responsive embed rendering; http-vs-https mixed-content. |
| CU-20 | SMS reminders/reconfirmation (Twilio); before/after_meeting sequence delivery; Resend delivery-log inspection; calendar event assertions (→ CU-03/04). |
| CU-22 | Chrome Web Store packed distribution; true cloud-sync latency/quota; Gmail DOM/class drift resilience; Firefox/Edge ports; plain-text compose insertion. |
3. Known blind spots (read this)
A few things no suite verifies, and a human should keep them in mind:
- Money paths are entirely untested. Stripe, PayPal, coupons, the Pro upgrade, and every Pro-gated feature (SMS reminders, custom domains, remove-branding) have no automated coverage at any tier because production has no test mode and the agent has no phone inbox or billing-safe account. Where these settings exist in the UI, only persistence is checked — never the effect. If a paid feature regresses, this suite will not catch it.
- The agent cannot inspect bytes it can't render. It does not parse
.icsfiles, recompute HMAC signatures, read raw HTTP response headers/status codes, or read encrypted values at rest in D1. So ICS DTSTART/DTEND correctness, webhook signature validity, exact CORS/X-Frame-Optionsheaders, soft-404 vs true-404, and BYOK key encryption are all asserted indirectly or handed to a human. - Time-gated delivery is structurally unprovable in a single run. 24h/1h reminders, reconfirmation windows, before/after-meeting sequences, and webhook retry/backoff/auto-disable all depend on cron crossing a future boundary; the suites verify configuration and persistence, not eventual delivery. Resend's actual delivery status (bounces, spam placement, non-Gmail rendering) is never visible to the agent.
- The "differentiator" is dark. The public AI booking chat is intentionally hidden in production (
display:none, floating widget not imported). CU-08 documents this honestly, but it means the marquee invitee-facing AI experience is effectively unshipped right now. - Self/cross-account and external-side-effect attribution is fuzzy. Invitees are plus-aliases of the host's own Gmail, so true separate-mailbox RSVP/invite delivery is ambiguous; round-robin side-effects route to the booking-page owner rather than the assigned member; and OAuth/Outlook flows collapse to manual residue the moment a cold login is required. These are correctly flagged, but they mean "the invitee really got X" is often an inference, not a proof.
- Subjective quality and real-device behavior are out of frame. Visual polish, typography, logo sharpness, SEO/OG cards, cross-browser rendering, and physical-device touch ergonomics are left to human eyeballing of screenshots — the agent only checks one emulated 375px viewport and the absence of console/overflow errors.