CU-14: Team / org scheduling: invite, roles, round-robin, collective, team page, audit log
Priority: P2 Accounts/sessions: P1 owner (ravikantguptaofficial@gmail.com, logged into Calendo via Google; Google Calendar connected; host notification inbox) + P3 teammate (everythingaichannelemail@gmail.com, must already have a Calendo account AND be logged into Calendo in a second browser profile/context) Parallel-safe: Yes (creates its own org + team event types scoped by RUNID; does not touch global host availability) Exclusive (rewrites global host availability?): No Estimated time: 40 minutes L3 reality checks: Yes — Gmail (confirmation to invitee plus-alias; host notification to P1) + Google Calendar event creation. IMPORTANT: see the L3 section — for a round-robin team event booked through the team page, the calendar event + host email land on the booking-page owner (P1), not necessarily the round-robin-assigned member. The assignment itself is an L2 (dashboard) check. Do not assert an email/GCal hit on the assigned member unless the booking was placed through that member's own booking slug.
Goal
This suite proves Calendo's team / organization scheduling end to end: an owner can create an org, add a teammate, assign and constrain roles, and publish team event types that schedule across multiple people. It verifies the two team scheduling modes — round-robin (booking rotates/assigns to the least-booked available member) and collective (a slot is only offered when all members are free) — plus the public team page that lists members and their bookable event types, and the per-user audit/activity log. This matters because team scheduling (round-robin sales calls, collective panel interviews) is the Phase 3 growth feature that lets Calendo serve teams, not just solo users; getting assignment, availability intersection/union, and permissions correct is what makes it trustworthy for real orgs.
Preconditions
- P1 Calendo session active in the primary browser context. Verify by loading https://calendo.dev/dashboard/ — the dashboard must render as P1 without a login prompt. If it shows the login page, STOP and flag a precondition failure per
00-setup-preconditions.md. Do NOT perform a cold Google/password login. - P3 Calendo session active in a SEPARATE browser context/profile. Verify by loading https://calendo.dev/dashboard/ in that context — it must render as P3 (everythingaichannelemail). If not, STOP and flag. Do NOT cold-login.
- P3 already has a Calendo account. The invite flow only adds an existing user immediately (response "Member added"); if P3 has never signed up, the invite becomes a pending email invitation with no auto-accept, and the round-robin/collective steps below cannot complete. If P3 is not a registered Calendo user, flag and stop — account creation is out of scope for this suite.
- P1 baseline availability exists (a default weekly schedule with at least some Mon–Fri working hours) and P1 Google Calendar is connected (Settings → Integrations shows Google Calendar connected). If either is missing, flag per
00-setup-preconditions.md— do not improvise availability. - P3 baseline availability exists (default weekly schedule). If P3 has no availability at all, the collective-mode intersection will be empty and that sub-check cannot pass; flag it but continue with round-robin.
- Gmail sessions active for both mail.google.com (P1 inbox = ravikantguptaofficial@gmail.com) and calendar.google.com (P1 calendar). If not logged in, flag — the L3 checks will be skipped, not faked.
- If ANY precondition is missing: record it in the results report as a precondition failure and SKIP the dependent steps. Do not work around a missing session by logging in.
Test data
RUNID convention: at execution time pick one fresh token, format YYYYMMDD-HHMM UTC, e.g. 20260601-1530. Use the SAME RUNID for every artifact in this run so reruns never collide and Gmail/Calendar searches can be scoped.
Create exactly these for this run (substitute the live RUNID):
- Org name:
CU14 Team <RUNID>→ org slug (auto-generated, confirm it):cu14-team-<RUNID>(lowercased, spaces→dashes) - Round-robin team event type: name
RR Sync <RUNID>, duration 30 min, mode Round Robin - Collective team event type: name
Collective Panel <RUNID>, duration 30 min, mode Collective - Round-robin invitee #1: name
RR Invitee One <RUNID>, emailravikantguptaofficial+inv-rr1-<RUNID>@gmail.com - Round-robin invitee #2: name
RR Invitee Two <RUNID>, emailravikantguptaofficial+inv-rr2-<RUNID>@gmail.com - Collective invitee: name
Coll Invitee <RUNID>, emailravikantguptaofficial+inv-coll-<RUNID>@gmail.com - Teammate to invite: P3 =
everythingaichannelemail@gmail.com, role member (then promoted to admin and demoted back to test role changes)
Steps
Phase A — Create the org and confirm owner controls (P1)
- Action: In the P1 context, open the dashboard (https://calendo.dev/dashboard/), then navigate to the Teams page (click the sidebar link "Team" which points to
/dashboard/team.html, or go directly to https://calendo.dev/dashboard/team.html). → Expect: The "Teams" heading is visible with a "+ New Team" button (#createOrgBtn). If no orgs exist yet, an empty-state "You haven't created or joined any teams yet." (#noOrgsMessage) shows. → [L1]
- Action: Click "+ New Team" (
#createOrgBtn). In the Create Team modal (#createOrgModal), type the org name into "Team Name" (#newOrgName) =CU14 Team <RUNID>. Confirm the "URL Slug" field (#newOrgSlug) auto-fills tocu14-team-<RUNID>. Click "Create" (#submitCreateOrg). → Expect: A toast "Team created" appears (#toast), the modal closes, and a new org card (.org-card) with nameCU14 Team <RUNID>, slug/cu14-team-<RUNID>, and roleownershows in the org list. → [L1] Capture screenshot:cu14-org-created
- Action: Click the new org card (
.org-card[data-org-id]) to open its detail view (#orgDetailView). → Expect: The org name shows as the page title (#orgName), a stats row (#orgStats) shows Members = 1, Bookings (30d) = 0, Event Types = 0, and the Members table (#membersTableBody) lists P1 (ravikantguptaofficial) with a role badgeowner(.role-badge.role-owner). The "+ Invite" (#inviteMemberBtn), "+ Create" team-event-type (#createTeamETBtn), and "Edit" (#editOrgBtn) buttons are all visible (owner has full control). → [L1] Capture screenshot:cu14-org-detail-owner
Phase B — Invite P3 and exercise roles
- Action: Click "+ Invite" (
#inviteMemberBtn). In the Invite Member modal (#inviteMemberModal), typeeverythingaichannelemail@gmail.cominto "Email Address" (#inviteEmail), leave Role (#inviteRole) on "Member". Click "Send Invite" (#submitInvite). → Expect: Because P3 is an existing Calendo user, the toast reads "Member added" (not "Invitation sent"). The members table now lists 2 rows: P1 (owner) and P3 (everythingaichannelemail) with role badgemember(.role-badge.role-member). Stats row Members = 2. → [L1] [L2] Capture screenshot:cu14-member-addedOrder note: P3 must be added before any team event type is booked, otherwise round-robin/collective has only one member and assignment cannot rotate.
- Action: Reload the org detail (click "Back to Teams"
#backToOrgsLink, then re-open the org card) to confirm membership persisted. → Expect: P3 still appears as amemberafter reload — confirms server-side persistence, not just optimistic UI. → [L2]
- Action: In P3's members-table row, click "Make Admin" (the role-toggle button rendered by
changeRole(...)— only the owner sees it). → Expect: Toast "Role updated"; P3's badge changes toadmin(.role-badge.role-admin). → [L1] [L2]
- Action: Switch to the P3 browser context. Open https://calendo.dev/dashboard/team.html and open the same org
CU14 Team <RUNID>. → Expect: As an admin, P3 SEES the "+ Invite" (#inviteMemberBtn) and "+ Create" team-event-type (#createTeamETBtn) and "Edit" (#editOrgBtn) buttons (admin can invite/edit/create). However, P3 must NOT see any role-change controls in the members table for P1 (only the owner can change roles —handleUpdateMemberRolereturns 403 for non-owners). → [L1] [L2] Capture screenshot:cu14-p3-admin-view
- Action: Back in the P1 context, demote P3: in P3's row click "Make Member" (
changeRole). → Expect: Toast "Role updated"; P3's badge returns tomember. → [L1]
- Action: Switch to the P3 context, reload the org detail. → Expect: As a plain member, P3 NO LONGER sees the "+ Invite", "+ Create" team-event-type, or "Edit" buttons (these are hidden for non-admin/owner via
isAdminOrOwnerinrenderOrgDetail). This proves the role demotion actually constrains P3's capabilities. → [L1] [L2] Capture screenshot:cu14-p3-member-constrainedNote: The frontend hides controls; the server also enforces 403 on the underlying endpoints (/api/organizations/:id/invite,.../members/:id). The agent verifies the UI constraint; the server-side 403 is noted under manual residue.
Phase C — Round-robin team event type (P1)
- Action: Back in P1 context, in the org detail click "+ Create" team event type (
#createTeamETBtn). In the Create Team Event Type modal (#createTeamETModal): Name (#teamETName) =RR Sync <RUNID>; Duration (#teamETDuration) = 30; Scheduling Mode (#teamETMode) = "Round Robin"; Description (#teamETDescription) =CU14 round robin <RUNID>. Click "Create" (#submitCreateTeamET). → Expect: Toast "Team event type created"; the Team Event Types list (#teamEventTypes) now shows a.team-et-cardwith nameRR Sync <RUNID>, meta30 min · rr-sync-<RUNID>, and a green mode badge (.mode-badge) readinground-robin. Stats row Event Types increments to 1. → [L1] Capture screenshot:cu14-rr-event-created
- Action: Find the public booking link for this team event. Open the public team page (see Phase E for the exact URL) OR construct it from the dashboard: the team event type is owned by P1, so its booking link is
https://calendo.dev/booking/?user=<P1_HOST_SLUG>&event=rr-sync-<RUNID>. To get<P1_HOST_SLUG>, read the dashboard booking link value (#bookingLinkValue) on the Overview tab — it is of the formhttps://calendo.dev/booking/?user=<P1_HOST_SLUG>. → Expect: You have a concrete booking URL containingevent=rr-sync-<RUNID>. → [L2]
- Action: Open the round-robin booking URL in a fresh (incognito/guest) browser context with no Calendo login. → Expect: The booking page (
#booking-view) loads showing the eventRR Sync <RUNID>, 30 min, with a calendar (.calendar-day.availabledays present). The available slots are the union of P1's and P3's availability (round-robin offers a slot if ANY member is free). → [L1]
- Action: Click the first available day (
.calendar-day.available), then the first time slot (.time-slot). Fill the booking form: Name (#input-name) =RR Invitee One <RUNID>, Email (#input-email) =ravikantguptaofficial+inv-rr1-<RUNID>@gmail.com. Click Confirm (#btn-confirm). → Expect: A confirmation screen with title (.confirmation-title) containing "Booking Confirmed". Note the booked date/time (record it asRR1_TIME). → [L1] Capture screenshot:cu14-rr-booking1-confirmed
- Action: In the same fresh context, re-open the round-robin booking URL and book a SECOND slot (a different time): first available day → first slot (
.time-slot) → Name (#input-name) =RR Invitee Two <RUNID>, Email (#input-email) =ravikantguptaofficial+inv-rr2-<RUNID>@gmail.com→ Confirm (#btn-confirm). → Expect: "Booking Confirmed". Record date/time asRR2_TIME. → [L1] Order note: Two bookings are needed to observe rotation. The first booking goes to the least-booked available member (tie broken by lowest user id); the second should shift toward the other member if both are free (pickRoundRobinMemberpicks fewest recent bookings).
- Action: In the P1 context, open the org detail again and read the Members table "Bookings (30d)" column (
booking_count_30dper member). → Expect: The two new round-robin bookings are attributed to members viaassigned_user_id: the combined Bookings(30d) across P1 + P3 increased by 2, and ideally the count is distributed across both members (e.g., P1 = 1, P3 = 1) rather than both landing on one member — demonstrating rotation. If both landed on the same member, note it; rotation depends on each member being free + least-booked at the chosen slots. → [L2] Capture screenshot:cu14-rr-assignment-stats
- Action: In the P1 context, go to the dashboard Bookings tab (sidebar
data-tab="bookings", https://calendo.dev/dashboard/ then Bookings). Locate the twoRR Sync <RUNID>bookings (search/scan for inviteeRR Invitee One <RUNID>andRR Invitee Two <RUNID>). → Expect: Both bookings appear with their invitee names/emails and the eventRR Sync <RUNID>. This confirms team bookings persist and are visible to the owner. → [L2] Capture screenshot:cu14-rr-bookings-dashboard
Phase D — Collective team event type (P1)
- Action: In P1 context org detail, click "+ Create" team event type (
#createTeamETBtn). Name (#teamETName) =Collective Panel <RUNID>; Duration (#teamETDuration) = 30; Mode (#teamETMode) = "Collective"; Description =CU14 collective <RUNID>. Click "Create" (#submitCreateTeamET). → Expect: Toast "Team event type created"; a.team-et-cardCollective Panel <RUNID>with mode badgecollective. → [L1] Capture screenshot:cu14-collective-event-created
- Action: Open the collective booking URL in a fresh context:
https://calendo.dev/booking/?user=<P1_HOST_SLUG>&event=collective-panel-<RUNID>. → Expect: The booking page loads. The offered slots are the intersection of P1's and P3's availability — i.e., only times when BOTH are free are bookable. Compared to the round-robin event (union), the collective event should offer fewer or equal available slots. If P1 and P3 have non-overlapping schedules, expect NO available days/slots (an empty calendar / "no times available" state) — that is correct collective behavior, not a bug. → [L1] [L2] Capture screenshot:cu14-collective-slots
- Action: If at least one collective slot is available, book it: first available day → first
.time-slot→ Name (#input-name) =Coll Invitee <RUNID>, Email (#input-email) =ravikantguptaofficial+inv-coll-<RUNID>@gmail.com→ Confirm (#btn-confirm). Record the time asCOLL_TIME. → Expect: "Booking Confirmed". If NO slots were available because schedules do not overlap, skip the booking and record "collective intersection empty (no overlapping availability)" as the observed (and acceptable) result. → [L1] Capture screenshot:cu14-collective-booking-confirmed(only if booked)
Phase E — Public team page
- Action: In the P1 context, go to the dashboard Settings tab (sidebar
data-tab="settings"), find the "Team Page" section (#teamPageSection) which lists each org's public URL (#teamPageLinks). The URL ishttps://calendo.dev/team/cu14-team-<RUNID>. Click "Copy Link" or "Open". (Alternatively just navigate directly to that URL.) → Expect: The Team Page section is visible and showsCU14 Team <RUNID>with the URLhttps://calendo.dev/team/cu14-team-<RUNID>. → [L1]
- Action: Open
https://calendo.dev/team/cu14-team-<RUNID>in a fresh (no-login) context. → Expect: The pretty URL 301-redirects tohttps://calendo.dev/team/?org=cu14-team-<RUNID>and renders the public team page: a header (#teamHeader) with org nameCU14 Team <RUNID>and subtitle "Choose a team member to schedule a meeting"; a members list (#membersList) with.member-cardentries. Under the relevant member (P1, who owns the team event types) the team event typesRR Sync <RUNID>andCollective Panel <RUNID>appear as.event-linkrows (each showing the name and "30 min"), each linking to/booking/<member_slug>?event=<event_slug>. → [L1] [L2] Capture screenshot:cu14-team-page-public
- Action: Click one of the event links (e.g.,
RR Sync <RUNID>) on the team page. → Expect: It navigates to that member's public booking page for the event (the same booking flow as Phase C). This confirms the team page's booking links are wired correctly. Do NOT complete another booking here unless needed; just confirm the booking view loads (#booking-view). → [L1]
Phase F — Audit / activity log
- Action: In the P1 context, go to Settings tab → "Activity Log" section (
#auditLogContainer, table#auditLogTable, body#auditLogBody). → Expect: A table of recent actions with Timestamp / Action / Details columns loads (not "Failed to load activity log"). → [L1]
- Action: In the "All actions" filter dropdown (
#auditActionFilter) select "Event type created" (valueevent_type.created) and click "Refresh" (#refreshAuditLogBtn). → Expect: The table showsEvent type createdrows, and entries for the two team event types created this run (details cell shows the slug, e.g.rr-sync-<RUNID>/collective-panel-<RUNID>) are present (they were logged vialogAuditEventon/api/event-typescreation). → [L1] [L2] Capture screenshot:cu14-audit-event-created
- Action: In the filter, select "Booking created" (value
booking.created) and click Refresh. → Expect: Rows for the round-robin (and collective, if booked) bookings appear; details cells include the invitee email (e.g.,...+inv-rr1-<RUNID>@gmail.com) and/or event name. → [L1] [L2] Capture screenshot:cu14-audit-booking-createdKnown limitation to record (not a failure): Org-level actions (org created, member invited, role changed) are NOT written to the per-user audit log by the current org handlers, so do not expect "organization created" / "member invited" rows. Only event_type/booking/login/settings-type actions appear. Record this observation.
L3 reality checks
Perform these AFTER the bookings are placed. Use the live RUNID in every query.
A. Gmail — invitee + host confirmation emails (P1 inbox).
- Open https://mail.google.com (P1 = ravikantguptaofficial@gmail.com).
- Search:
inv-rr1-<RUNID>→ Expect: A "Booking Confirmed"-style confirmation email addressed to/aboutravikantguptaofficial+inv-rr1-<RUNID>@gmail.comforRR Sync <RUNID>atRR1_TIME. Open it and confirm it contains the event name, date/time, and a manage/cancel link (/booking/cancel.html?token=...). → [L3] - Search:
inv-rr2-<RUNID>→ Expect: Confirmation email for the second round-robin booking atRR2_TIME. → [L3] - If a collective booking was placed, search:
inv-coll-<RUNID>→ Expect: Confirmation email forCollective Panel <RUNID>atCOLL_TIME. → [L3] - Search:
RR Sync <RUNID>→ Expect: The host notification email(s) delivered to P1 (host), confirming the host inbox received the new-booking notice. → [L3] Capture screenshot:cu14-gmail-confirmations
B. Google Calendar — real event creation (P1 calendar).
- Open https://calendar.google.com (P1).
- Navigate to the date/time of
RR1_TIME. → Expect: A real calendar event titled withRR Sync <RUNID>(or "<event name> with RR Invitee One <RUNID>") exists at that slot, with the inviteeravikantguptaofficial+inv-rr1-<RUNID>@gmail.comlisted as a guest/attendee. → [L3] - Navigate to
RR2_TIME→ Expect: A second event for the round-robin booking. → [L3] - If collective was booked, navigate to
COLL_TIME→ Expect: ACollective Panel <RUNID>event. → [L3] Capture screenshot:cu14-gcal-events
IMPORTANT accuracy caveat for "email/GCal to the ASSIGNED member": In current production, the booking side-effects (Google Calendar event creation + host notification email) run against the booking-page owner of the slug the invitee used — here that is P1, because the team event types are owned by P1 and surfaced under P1's booking slug. The round-robin assignment (assigned_user_id, which may be P3) is recorded in the database and reflected in the dashboard org stats (Phase C step 15) but does NOT redirect the calendar event/email to the assigned member. Therefore:
- The L3 calendar/email checks above are scoped to P1's Google Calendar and Gmail and WILL pass there.
- A true L3 check that the GCal event / email landed on P3's calendar/inbox is NOT expected to pass for a team-page round-robin booking and must NOT be asserted as a pass. If you want to observe an assigned-member-scoped calendar hit, that requires the team event to be booked through P3's own booking slug — out of scope here. Record the assignment result as an L2 (dashboard) fact, and record this routing behavior under manual residue.
Cleanup
Do all cleanup as P1 (owner) unless noted. The goal is to leave both Google accounts and Calendo clean for the next run.
- Cancel the round-robin bookings. From the confirmation emails (Gmail searches
inv-rr1-<RUNID>,inv-rr2-<RUNID>) open each booking's cancel link (/booking/cancel.html?token=...) and cancel, OR cancel from the P1 dashboard Bookings tab (data-tab="bookings") using the per-booking Cancel action. → Confirm each shows cancelled. - Cancel the collective booking (if placed): Gmail search
inv-coll-<RUNID>→ open cancel link → cancel. - Verify in Google Calendar that the cancelled bookings' events were removed from P1's calendar at
RR1_TIME,RR2_TIME, andCOLL_TIME(cancellation should delete/decline the GCal event). If any orphan event remains, delete it manually in calendar.google.com. - Delete the team event types. In the org detail (team.html), there is currently no in-UI delete for team event types; delete them from the dashboard Event Types tab (
data-tab="event-types") by opening each (RR Sync <RUNID>,Collective Panel <RUNID>) and using its delete action, OR leave them only if no delete control exists — in that case set them inactive so they drop off the public team page, and record the residue. - Remove P3 from the org. In org detail members table, click "Remove" on P3's row (
removeMember(...)), confirm the browser prompt. → P3 should disappear from the members list. - Delete the org. If team.html exposes no org-delete control (it does not in the current UI), the org cannot be deleted via the browser — record
org cu14-team-<RUNID> left in place (no UI delete)under manual residue so the human can remove it via API/D1 if desired. Ensure at minimum that all member rows except the owner are removed and event types are inactive so the public team page is empty. - Confirm Gmail/Calendar are clean: re-run the Gmail searches
inv-rr1-<RUNID>,inv-rr2-<RUNID>,inv-coll-<RUNID>and confirm only the cancellation emails (not active bookings) remain; confirm no live events atRR1_TIME/RR2_TIME/COLL_TIMEin P1's calendar.
Pass/Fail criteria
The run PASSES only if ALL of the following are true:
- Org
CU14 Team <RUNID>was created with slugcu14-team-<RUNID>and P1 shown asowner. [L1/L2] - P3 was added as a
member(toast "Member added") and persisted across reload. [L2] - Role change works: P3 promoted to
admin(sees invite/create/edit controls) and demoted tomember(those controls disappear); a non-owner never sees role-change controls. [L1/L2] - Round-robin team event
RR Sync <RUNID>(mode badgeround-robin) was created and its public booking page offered slots (union of member availability). [L1] - Two round-robin bookings were confirmed and are visible in the P1 dashboard; the org members' Bookings(30d) increased by 2, attributed via
assigned_user_id(rotation observed, or single-member attribution explained by availability). [L2] - Collective team event
Collective Panel <RUNID>(mode badgecollective) was created and its booking page offered only intersection slots — strictly ≤ the round-robin event's slot count for the same range (or empty if no overlap), never more. [L1/L2] - The public team page at
https://calendo.dev/team/cu14-team-<RUNID>rendered the org name, member(s), and the team event types with working/booking/...?event=...links. [L1/L2] - The Activity Log shows
event_type.createdrows for both team event types andbooking.createdrows for the bookings (with invitee email in details). [L1/L2] - L3: confirmation emails for each booked invitee plus-alias and a host notification for P1 were found in Gmail, AND the corresponding real events exist in P1's Google Calendar at the booked times with the invitee as a guest. [L3]
- Cleanup completed: all RUNID bookings cancelled, their GCal events removed, P3 removed from the org, team event types deleted or made inactive.
The run FAILS if: any precondition session was missing and had to be cold-logged-in; round-robin offered no union slots while members had availability; collective offered MORE slots than round-robin (intersection broken); the team page 404s or omits the team event types; the audit log fails to load or lacks the event_type/booking entries; or no confirmation email / GCal event appeared for a confirmed booking.
Evidence to capture
- Screenshots:
cu14-org-created,cu14-org-detail-owner,cu14-member-added,cu14-p3-admin-view,cu14-p3-member-constrained,cu14-rr-event-created,cu14-rr-booking1-confirmed,cu14-rr-assignment-stats,cu14-rr-bookings-dashboard,cu14-collective-event-created,cu14-collective-slots,cu14-collective-booking-confirmed(if booked),cu14-team-page-public,cu14-audit-event-created,cu14-audit-booking-created,cu14-gmail-confirmations,cu14-gcal-events. - Notes to record: the live RUNID; the resolved org slug;
<P1_HOST_SLUG>;RR1_TIME,RR2_TIME,COLL_TIME; the per-member Bookings(30d) split observed (rotation result); whether collective had overlap or was empty; whetherbooking.created/event_type.createdaudit rows were found; confirmation that org-level actions are absent from the audit log; and whether GCal/email landed on P1 (page owner) vs the assigned member.
Manual residue / cannot-verify
- Assigned-member-scoped L3: Whether the round-robin assigned member (potentially P3) actually received the calendar event/host email cannot be confirmed in-browser for a team-page booking, because production routes side-effects to the booking-page owner (P1), not the assigned member. The assignment is verified only at L2 (dashboard stats /
assigned_user_id). A human must inspect D1 (bookings.assigned_user_id) or P3's calendar via a member-slug booking to fully verify assignment-driven notifications. - Server-side 403 enforcement of roles: The agent verifies that role demotion hides UI controls, but cannot easily confirm the backend returns 403 on
/api/organizations/:id/inviteand.../members/:idfor a non-owner/non-admin without crafting raw requests. Human/API check recommended. - Org deletion + team-event-type deletion: The current team.html UI exposes no delete control for the org itself or for team event types; cleanup may leave the org (and possibly the team event types, if only made inactive) in place. A human should remove them via the API/D1 if a fully clean slate is required.
- Org-level audit logging: Org create / member invite / role change are not written to the audit log by current handlers; their absence is expected, but if audit coverage of org actions is desired that is a product gap for the human to note.
- Round-robin rotation determinism: Rotation depends on member availability and least-booked tie-breaking; on a given run both bookings may legitimately land on one member (e.g., the other was busy). The agent records the split but cannot force a specific rotation in-browser.
- Pending-invitation email path: Because P3 is an existing user (auto-added), the email-based pending-invitation acceptance flow (
org_invitations, invite token) is NOT exercised by this suite — out of scope / TBD.