ADR 0002. Random Pairwise External IDs (not derived from internal UUID)
Status
Accepted for generation and encoding. Partner-facing prefix superseded by
ADR 0013: 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),
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:
- Encode the internal UUID directly (
Base32(internal_uuid)), or derive the external ID deterministically viaHMAC(secret, internal_id + audience_id). - 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.