Preconditions
Organizer can view and edit the event guest list; fixture event has invited, confirmed, declined, and cancelled guests.
Happy path / Lifecycle
Open a guest from the guest table.
The drawer shows identity fields, invitation/response state, access type, ticket count, notes, and custom responses.
Edit contact and response data.
Save patches only changed fields through the guest route and refreshes the row in place.
Cancel or restore a guest response.
Destructive response changes are explicit and reversible during the undo window.
Failure modes
Permission denied at the right boundary
Trigger: support/viewer role tries to edit a guest.
Resolution: 403, drawer is read-only or closed, and no guest PII is leaked beyond role scope.
Cross-tenant isolation
Trigger: organizer guesses a guest id from another tenant.
Resolution: 404 response masks existence and omits guest identity.
Soft-delete leaves audit trail
Trigger: organizer removes a guest.
Resolution: guest is soft-deleted/cancelled with audit row containing actor, timestamp, and prior state.
Archive vs delete distinction
Trigger: organizer cancels attendance versus removes the guest record.
Resolution: cancel preserves the invitation/contact record; delete is destructive and separately confirmed.
Edit lock during publish
Trigger: publish/export snapshot starts while guest edit is open.
Resolution: snapshot wins; stale save gets conflict UI and does not change the exported guest state silently.
Audit row on every state change
Trigger: contact, access type, ticket count, note, custom field, invite state, or response changes.
Resolution: audit row records field-level before/after values.
Two organizers concurrent
Trigger: two organizers edit the same guest drawer.
Resolution: version conflict prevents silent overwrite and both see final persisted state after refresh.
Undo window for destructive actions
Trigger: organizer cancels a response or removes a guest.
Resolution: 10 second undo restores the prior status and audit records the restoration.
Capacity revalidation
Trigger: organizer increases a guest's ticket count beyond remaining capacity.
Resolution: save is blocked with a capacity-specific inline error.
Invitation status mismatch
Trigger: organizer changes access type for a guest with an old invite token.
Resolution: old token is invalidated or rebound deterministically, and the drawer shows whether resend is needed.
Stable test attributes
Visibility teeth. Each attribute must be effectively visible when active.
| data-test | Where | Purpose |
|---|---|---|
guest-list-page | Route | Guest list root |
guest-row | Table | Each guest |
guest-edit-drawer | Drawer | Edit surface |
guest-edit-form | Drawer | Patch form |
guest-email-input | Form | |
guest-response-picker | Form | Response state |
guest-ticket-count-stepper | Form | Ticket count |
guest-edit-save-cta | Form | Save |
guest-cancel-response-cta | Drawer | Cancel response |
guest-delete-cta | Drawer | Remove guest |
guest-edit-undo-toast | Toast | Undo destructive action |
guest-edit-conflict-modal | Modal | Conflict |
guest-edit-validation-error | Form | Inline validation |
Agent test plan
- guest-list-renders
- edit-guest-save
- cancel-response
- permission-denied-boundary
- cross-tenant-404
- soft-delete-audit
- archive-delete-distinction
- publish-edit-lock
- audit-row-every-change
- concurrent-organizers-conflict
- destructive-undo-window
- capacity-revalidation
- invitation-status-mismatch