Preconditions
Inherits public-event-page with page-resolves. Organizer-side transfer configuration and the sender's authenticated flow are out of scope; this branch starts when the recipient opens a transfer link.
Happy path
Recipient opens
/p/:slug/transfer?token=....The page validates the transfer token and shows event identity plus the sender name if the sender opted to disclose it.
Recipient accepts.
The form collects recipient name and email, then atomically moves the ticket entitlement from sender to recipient.
Confirmation renders.
The recipient sees a confirmed registration; the old token is marked consumed and safe to re-open.
Failure modes
Capacity full mid-fill
Trigger: transfer acceptance starts while capacity is available, but the destination access type fills before submit.
The 409 state explains the event just filled and offers waitlist placement if enabled. The token remains unconsumed unless the waitlist conversion succeeds.
Two-tab idempotency
Trigger: recipient opens the same transfer link twice and accepts both.
The transfer token is consumed once. The second tab shows the existing accepted transfer and does not create a second registration or re-remove sender entitlements.
Network drop during submit
Trigger: accept POST succeeds but response is lost.
Retry with the same Idempotency-Key returns the accepted transfer. Sender and recipient states remain exactly once.
Invalid input rejected without info leak
Trigger: fake transfer token or garbage event slug.
Malformed, unknown, expired-looking, and wrong-event tokens render the same generic transfer-unavailable page.
Source page archived, draft, or deleted
Trigger: transfer link resolves structurally, but the destination event is archived, draft, or deleted.
The transfer page returns one generic 4xx-style unavailable state and does not reveal which event lifecycle state caused it.
Browser back after success
Trigger: recipient accepts, sees confirmation, then presses back.
The accept form does not resubmit. It renders a read-only already-accepted state for the transfer token.
Open Graph tags present
Trigger: recipient shares the transfer URL.
OG tags use the canonical event URL and hero image. The transfer token, sender, and recipient email never appear in metadata.
Bot-fill rate-limited
Trigger: one IP submits transfer accept attempts repeatedly.
The page surfaces 429 or captcha. The token remains unconsumed and the response does not reveal whether the token was valid.
Recipient declines
Trigger: recipient clicks Decline.
The token moves to declined, sender keeps or regains the entitlement per policy, and re-clicking the link shows declined status rather than the accept form.
Sender cancels mid-flow
Trigger: sender revokes the transfer while recipient is typing.
Submit returns a generic unavailable state with no blame and no disclosure of sender action timing.
Recipient email already registered
Trigger: recipient accepts using an email already confirmed for the event.
The server prevents duplicate registration and shows an already-registered transfer resolution. It does not overwrite the existing registration without explicit support.
Stable test attributes
Visibility teeth. Each attribute must be visible when the transfer page is in that state.
| data-test | Where | Purpose |
|---|---|---|
transfer-page | Transfer URL | Root transfer acceptance page |
transfer-form | Inside transfer page | Recipient accept form |
transfer-recipient-name | Inside form | Recipient name input |
transfer-recipient-email | Inside form | Recipient email input |
transfer-accept-cta | Inside form | Accept transfer |
transfer-decline-cta | Inside transfer page | Decline transfer |
transfer-confirmation | Accepted state | Confirmed transfer summary |
transfer-already-accepted | Consumed token state | Existing accepted transfer |
transfer-declined | Declined state | Declined transfer summary |
transfer-unavailable | Invalid/revoked/unavailable state | Generic transfer unavailable page |
transfer-capacity-full | 409 state | Filled while accepting message |
transfer-waitlist-cta | Capacity state | Join waitlist instead |
transfer-rate-limit | 429 state | Retry-after or captcha message |
transfer-already-registered | Duplicate recipient state | Recipient already registered message |
Agent test plan
Start from a fixture transfer token and verify accept, decline, consumed token, revoked token, duplicate recipient, capacity race, and anti-probing variants. Sender-side configuration remains a separate organizer branch gap.