Skip to main content
InternalMarkdown

ADR 0026. Random Analytics Subject and Provider-Global Cohort (not alias)

Status​

Accepted.

Does not change ADR 0014: a provider-global alias remains forbidden by default. This record allows a provider-global cohort (Account counts, numbers only).

Context​

Partners want enrichment without correlating a person across Audiences. Two tempting shortcuts both fail the identity invariants:

  1. Hang partner analytics off players.id or expose UUID / pp_plr_... / another Audience’s alias on a partner read.
  2. Mint one pp_plr_prv_... per provider so that provider can join the same person across operators. ADR 0014 already rejects that default.

A third need appears at Delete Account: gameplay facts may be retained, but the live UUID join must disappear. A PlayerPal-only clustering key is required so retained Activity is not re-attached to a person on a partner API, and so studio KPIs can count distinct Accounts rather than aliases.

Deriving that key from UUID or pp_plr_... would make it reversible. Summing per-alias serving rows would double-count a Player with two integrations at the same provider.

Decision​

  1. Mint a cryptographically random analytics subject (pp_anl_...) at Account activation. Never derive it from UUID, pp_plr_..., PII, or a partner identifier. Never return it on player or partner APIs (including /v1/me, link exchange, activity ingest, and studio reads).
  2. Live loyalty processing may use Account id in memory. Persisted partner-facing analytics and serving rows must not expose Account id. Partner studio HTTP is machine-authenticated and provider-Party scoped (x-party-id as pp_prv_...), not ingest’s x-integration-id, and not a payload operator_id.
  3. Per-alias studio lookup uses only a pp_plr_prv_... that provider was issued. A foreign alias is the same unknown as a missing alias. Two aliases for the same Account at that provider return the same Account-level numbers. “On you” is all of that provider’s integrations for the Account, not one casino. Response body is numbers only: from, to, bets, wins, bet_eur, share_of_their_slot_turnover, rounds_on_you, rounds_elsewhere.
  4. Studio rollup counts distinct Accounts for that provider Party and is not implemented as a sum of per-alias serving rows. It includes accounts. Windows below a configurable Account floor are suppressed (production default 50; tests/demo may lower it). Per-alias lookup is n=1 by design.
  5. Unlink freezes new partner-player-day rows for that alias; historical days remain. Delete Account deletes partner-player-day (and related serving) rows for that Player’s aliases, nulls player_id / player_alias on retained Activity, destroys the UUID↔analytics-subject mapping, and leaves round_ref and the analytics subject on retained facts. Live per-alias GET for those aliases is unknown.
  6. v1 stores UUID↔analytics-subject in application storage. Crypto-shredding / KMS envelope encryption is out of scope. A restored pre-delete backup can still join; do not market otherwise.

Consequences​

  • ADR 0014 still governs aliases. Open question 5 (which providers, if any, get a provider-global alias exception) stays open. Cohort is not that exception.
  • Identity and loyalty topic pages must not say partner analytics hang off players.id. Internal ledger and identity tables still may.
  • Closes open question 6 for output (numeric cohort and per-alias enrichment; never another Audience’s identifier) and open question 7 (Unlink vs Delete Account retention). Legal joint-controller contracts stay a product-permission assumption, not an identifier rule.
  • Glossary: CONTEXT.md. Day-to-day: docs/loyalty.md, docs/identity.md. Unlink skeleton: spec §36.6.