Preconditions
Organizer admin can access tenant Address Book; fixture includes duplicate email contacts, tagged contacts, and contacts with event activity.
Happy path
Open Address Book contacts.
A searchable, filterable table lists reusable contacts independently of a single event.
Create or edit a contact.
The form captures identity, email, phone, address, tags, notes, privacy fields, and custom fields.
Merge duplicate contacts and inspect history.
Duplicate email merge preserves event invitation and attendance history with auditable before/after state.
Failure modes
Permission denied at the right boundary
Trigger: viewer edits a contact.
Resolution: 403, edit controls disabled, no hidden PII leaks.
Cross-tenant isolation
Trigger: tenant A user guesses tenant B contact id.
Resolution: 404 masks contact existence.
Soft-delete leaves audit trail
Trigger: organizer deletes a reusable contact.
Resolution: contact is soft-deleted with actor, timestamp, and prior state.
Archive vs delete distinction
Trigger: organizer archives a contact versus deletes it.
Resolution: archive hides from default invite flows; delete is destructive and separately confirmed.
Edit lock during concurrent operations
Trigger: contact merge starts while edit drawer is open.
Resolution: stale save gets conflict modal and cannot unmerge data.
Audit log row on every state change
Trigger: contact identity, tags, notes, merge, archive, or delete changes.
Resolution: contact audit row records field-level before/after.
Two organizers concurrent
Trigger: two organizers edit the same contact.
Resolution: version conflict prevents silent overwrite.
Undo window for destructive actions
Trigger: contact archive, delete, or merge is submitted.
Resolution: 10 second undo restores the exact prior contact set when permitted.
Duplicate email merge loses event history
Trigger: same email appears in two reusable contacts.
Resolution: merge keeps all invitation, attendance, RSVP, and note lineage.
Contact history missing or incomplete
Trigger: organizer opens activity panel for a reused contact.
Resolution: gap panel stays visible until event invitation and attendance history render by contact.
Tag and note privacy bleed
Trigger: private note exists on a contact reused across events.
Resolution: note visibility follows tenant/admin role and never appears on public registration.
Capability gap: full Address Book UI missing
Trigger: matrix marks EF-004 partial.
Resolution: visible gap panel remains until reusable contact UI and contact-event history are complete.
Stable test attributes
Visibility teeth. Each attribute must be effectively visible when active.
address-book-contacts-page | Page | Contacts root |
address-book-contact-table | Page | Contacts table |
address-book-contact-search | Toolbar | Search and filters |
address-book-contact-pagination | Footer | Pagination |
address-book-contact-bulk-bar | Toolbar | Bulk actions |
address-book-contact-form | Drawer | Create/edit form |
address-book-contact-email-input | Form | Email input |
address-book-contact-delete-cta | Drawer | Delete contact |
address-book-contact-merge-modal | Modal | Merge duplicates |
address-book-contact-history-panel | Drawer | Event history |
address-book-contact-gap-panel | Page | Partial gap |
address-book-contact-undo-toast | Toast | Undo destructive action |
Agent test plan
- contacts-table-renders
- contact-create-or-edit
- contact-merge-history
- permission-denied-boundary
- cross-tenant-404
- soft-delete-audit
- archive-delete-distinction
- merge-edit-lock
- audit-row-every-change
- concurrent-organizers-conflict
- destructive-undo-window
- duplicate-merge-preserves-history
- contact-history-gap
- tag-note-privacy
- contacts-gap-probe
- evaluate-address-book-contacts