# ADR 0002. Random Pairwise External IDs (not derived from internal UUID)

## Status
Accepted for generation and encoding. Partner-facing **prefix** superseded by
[ADR 0013](0013-typed-pairwise-aliases.md): operators receive `pp_plr_opr_...`,
providers receive `pp_plr_prv_...`, and `pp_plr_...` is player-visible only.

Random 128-bit pairwise values, Crockford Base32, stored mapping, and rejection
of `Base32(internal UUID)` / HMAC derivation still stand. Aliases are generated
when the one-time link completes ([ADR 0009](0009-mandatory-one-time-link-before-data-flows.md)),
not at passive first exposure.

## Context
PlayerPal's core privacy requirement: no partner may correlate the same
player across other partners. Two generation strategies were evaluated:

1. Encode the internal UUID directly (`Base32(internal_uuid)`), or derive
   the external ID deterministically via `HMAC(secret, internal_id + audience_id)`.
2. Generate a **fresh, unrelated random 128-bit value per (player, audience)
   pair**, store the mapping, and Base32-encode it for external use.

Option 1's first variant (direct encoding) is reversible. Anyone holding
it can decode back to the same internal UUID, which is then a shared,
correlatable value across every partner. This would have violated the
privacy requirement outright and was caught before implementation.

The HMAC variant avoids exposing the UUID but introduces its own problems:
secret management becomes safety-critical, key rotation is hard, and a
mapping table ends up being useful anyway for audit/lifecycle purposes,
undercutting the main reason to derive rather than store.

## Decision
Use **random pairwise IDs**: a fresh cryptographically random 128-bit
value per `(subject_party_id, audience_party_id)` pair, generated at
first exposure, stored in `party_identifier`, and rendered externally as
`pp_<type>_<Crockford-Base32(random 128 bits)>`.

## Consequences
- Requires a stored mapping lookup (acceptable trade-off; also needed for
  revocation/rotation and audit regardless).
- Strong unlinkability: no mathematical relationship between a player's
  aliases across different audiences.
- Alias can be revoked/rotated per-audience without affecting others.
- Compromise of one audience's alias mapping does not reveal another
  audience's alias for the same player.
- Internal IDs remain UUIDv7 (time-ordered, index-friendly, native DB
  support); only the *external* representation uses random pairwise
  values, never a transform of the internal ID.
