Experimentos

Los experimentos son una forma de pruebas A/B que utiliza Discord tanto del lado cliente como del servidor en sus aplicaciones para mostrar diferentes experiencias o comportamientos a usuarios diferentes aleatoriamente y/o basados en la ubicación, versión del cliente, etc.

En esencia, las implementaciones (rollouts) son simplemente YAML introducido en el panel administrativo de Discord; sin embargo, no todos los datos son requeridos por los clientes. Por eso los experimentos que los clientes ven están minificados y resultan complejos de descifrar.

Huella Digital

Incluso el sitio web de marketing utiliza tests A/B para atraer usuarios a la app. Por ello, la aplicación necesita una forma única de identificar a quien usa la web sin usar autenticación (para usuarios que inicialmente visitan la landing page), así que recurre a "fingerprints" o huellas digitales.

Estas no son las típicas fingerprints generadas por información del navegador; son snowflakes generados por peticiones no autenticadas a obtener asignaciones de experimento. Se espera que las fingerprints se envíen en la cabecera X-Fingerprint en todas las peticiones posteriores a la API hasta autenticarse, para rastrear las pruebas A/B y permitir el acceso a partes de experimentos limitadas por API.

Una fingerprint consiste en un snowflake y un valor criptográfico hasheado. Tiene este aspecto: 1084179945133187083.JQddgNMmwJPghoBtFmaH7jTmdsw.

Al registrar una nueva cuenta, la fingerprint se pasa, y (si es válida) se utiliza como ID del usuario creado. Esto es para preservar los experimentos en el usuario que acaba de registrarse. Por tanto, el tiempo de creación de una cuenta teóricamente representa la primera vez que visitó la web de marketing de Discord.

Implementaciones

Las implementaciones de experimentos se definen en poblaciones basadas en la posición de implementación del usuario o servidor y pueden tener filtros que limiten la disponibilidad de cada población.

Ejemplo de implementación

2023-02_stage_boosting (1816004721)

### Treatment 1

Filters

Guild Features: [COMMUNITY]
Member Count Range: 1000 - null
Hash Range: Hash Key: 1816004721, Target: 10000

Position Ranges

5000-9500, 9500-10000

### Control

Filters

Guild Features: [COMMUNITY]
Member Count Range: 1000 - null

Position Ranges

0 - 10000

### None

Position Ranges

0 - 10000

Tratamientos

Control y None están representados en la API como los valores enteros 0 y -1, respectivamente. Como advertencia, hay instancias donde ciertos experimentos tienen tratamientos innecesarios etiquetados como Control indexados como 1.

Posiciones de implementación

Una posición de implementación se calcula con el siguiente seudocódigo, donde exp_name es el nombre del experimento y resource_id es el ID de usuario, fingerprint o servidor. Esta posición se usa junto con las poblaciones y filtros para averiguar a qué bucket ha sido asignado el experimento simplemente comprobando en qué tratamiento entra la población.

result = mmh3.hash('exp_name:resource_id', signed=False) % 10000

Estructuras de datos

Hay dos tipos de experimentos, experimentos de usuario y experimentos de servidor. Los metadatos y nombres legibles por humanos están disponibles en los clientes. En la API los objetos no traen estos datos, salvo los experimentos de servidor, que pueden tener el nombre para el hash.

La mayoría de los objetos siguientes están representados como arrays siguiendo el orden documentado en los campos.

Experimentos de usuario

La información devuelta por la API sobre experimentos de usuario es muy limitada. En contraste con la variedad de datos de los rollouts de servidor, solo obtenemos el bucket asignado al usuario o la huella digital.

Estructura de experimento de usuario

Este objeto es un array de los siguientes campos:

1 El bucket para experimentos A/A test debe ser None (-1) salvo que haya sobrescritura para el recurso.

2 La información de holdout está presente solo si hay bucket asignado. Si hay holdout y el bucket es None (-1), el experimento está deshabilitado por el holdout. Los clientes pueden omitir este campo y solo seguir el campo population como siempre.

Campo
Tipo
Descripción

hash

integer

Hash Murmur3 de 32 bits sin signo del nombre del experimento.

revision

integer

Versión actual del rollout.

bucket

integer

El bucket experimental asignado al usuario o fingerprint.

override

integer

Indica si el usuario o fingerprint tiene sobrescritura para el experimento (-1 falso, 0 verdadero).

population

integer

El grupo interno de población al que pertenece el usuario o fingerprint.

hash_result

integer

La posición de implementación calculada a usar, priorizada a cálculos locales.

aa_mode 1

integer

Modo A/A testing, representado como booleano entero.

trigger_debugging

integer

Indica si trigger debugging de análisis está activado (booleano entero).

holdout_name 2

?string

Nombre legible de un experimento (formato año-mes_nombre) que deshabilita el experimento.

holdout_revision 2

?integer

Revisión del experimento holdout.

holdout_bucket 2

?integer

Bucket experimental asignado para el experimento holdout.

Ejemplo de experimento de usuario

[826493636, 3, -1, -1, 0, 203, 0, 1, "2025-02_user_profile_editing", 2, 0]

Objeto de población experimental

Define los filtros y rangos de posición que debe cumplir una población.

Estructura de objeto de población experimental

Es un array de los siguientes campos:

Campo
Tipo
Descripción

ranges

array[objeto rango de población experimental]

Los rangos para esta población.

filters

objeto de filtros de población experimental

Los filtros que el recurso debe cumplir para entrar en la población.

Ejemplo población experimental

[
  [
    [
      -1,
      [
        {
          "s": 7200,
          "e": 10000
        }
      ]
    ]
  ],
  [
    [
      2294888943,
      [
        [2690752156, 1405831955],
        [1982804121, 10000]
      ]
    ]
  ]
]

Objeto de rango de población experimental

Si los filtros de la población son válidos y el rango incluye la posición de rollout, el recurso es elegible para ese bucket.

Estructura de objeto de rango de población experimental

Este objeto se representa como un array de los siguientes campos:

Campo
Tipo
Descripción

bucket

integer

El bucket que otorga este rango.

rollout

array[objeto rollout de población experimental]

El rango del rollout.

Estructura rollout de población experimental

Campo
Tipo
Descripción

s

integer

El inicio de este rango.

e

integer

El final de este rango.

Ejemplo de rango de población experimental

[
  1,
  [
    {
      "s": 0,
      "e": 4750
    }
  ]
]

Objeto de filtros de población experimental

Define los filtros necesarios para ser elegible para los rangos. Todos los filtros deben cumplirse para que el recurso sea elegible al bucket.

Los filtros son un objeto representado como array de arrays. El primer elemento del array anidado es el key hash, el segundo el valor. El orden es siempre el documentado aquí.

Estructura filtros poblacionales experimentales

Campo
Tipo
Descripción

guild_has_feature?

objeto filtro feature de servidor

Las features del servidor elegibles.

guild_id_range?

objeto filtro rango por ID

Rango de IDs de recurso elegibles.

guild_age_range_days? 1

objeto filtro rango por días

Rango de días de vida del servidor elegibles.

guild_member_count_range?

objeto filtro rango por miembros

Rango de cantidad de miembros elegibles.

guild_ids?

objeto filtro por ID

Lista de IDs de recurso elegibles.

guild_hub_types?

objeto filtro tipos de hub

Lista de tipos de hub elegibles.

guild_has_vanity_url?

objeto filtro vanity url

Si el servidor debe tener vanity url para ser elegible.

guild_in_range_by_hash?

objeto filtro por hash/rango

Límites especiales de posición de implementarción.

1 La edad del servidor se determina por el ID. Consulta la documentación de snowflake. Puede calcularse así:

timestamp = ((resource_id >> 22) + 1420070400000) / 1000
guild_age = (time.time() - timestamp) / 86400

Estructuras de filtros

Campo
Tipo
Descripción

guild_features

array [string]

Las funcionalidades del servidor elegibles; con que tenga una basta.

Estructura filtro rango por hash

Este filtro se utiliza para limitar la posición de implementación (rollout) mediante una clave hash adicional. La posición de implementación calculada debe ser menor que el objetivo proporcionado. La posición de implementación puede calcularse utilizando el siguiente pseudocódigo, donde hash_key es la clave hash proporcionada y resource_id es el ID de la guild:

hashed = mmh3.hash('hash_key:resource_id', signed=False)
if hashed > 0:
    # Double the hash
    hashed += hashed
else:
    # Unsigned right shift by 0
    hashed = (hashed % 0x100000000) >> 0
result = hashed % 10000
Campo
Tipo
Descripción

hash_key

integer

Hash Murmur3 de 32 bits sin signo usado para determinar elegibilidad.

target

integer

Límite de posición para esta población.

Ejemplo filtros de población experimental

[
  [
    1604612045, // guild_has_feature
    [
      [
        1183251248, // guild_features
        ["ROLE_SUBSCRIPTIONS_ENABLED"]
      ]
    ]
  ]
]

Objeto de sobrescritura de bucket experimental

Una sobrescritura representa el ajuste manual por empleados de Discord para dar acceso temprano o concreto a un experimento.

Estructura de sobrescritura de bucket experimental

Campo
Tipo
Descripción

b

integer

Bucket asignado a estos recursos.

k

array [snowflake]

Recursos que se les concede acceso a este bucket.

Ejemplo de Sobrescritura de Bucket

{
  "b": 1,
  "k": ["882680660588904448", "882703776794959873", "859533785225494528", "859533828754505741"]
}

Endpoints

Obtener asignaciones de experimento

GET /experiments

Devuelve las asignaciones de experimento de usuario y opcionalmente los rollouts de servidor para el usuario o fingerprint.

Los experimentos devueltos dependen de las propiedades del cliente.

Parámetros de cadena de consulta

1 Incluir este parámetro requiere autenticación válida.

Campo
Tipo
Descripción

with_guild_experiments?

boolean

Si devolver experimentos de servidor en la respuesta.

platform? 1

string

Si incluir experimentos para la plataforma dada.

Plataforma de experimentos

Valor
Descripción

DEVELOPER_PORTAL

El portal de desarrolladores.

Cuerpo de respuesta

Campo
Tipo
Descripción

fingerprint?

string

Una fingerprint generada de la fecha y hora actual.

assignments

Asignaciones de experimento para ese usuario o fingerprint.

guild_experiments?

Rollouts experimentales de servidor para el cliente asignar.

Crear fingerprint

POST /auth/fingerprint

Obsoleto

Genera una nueva fingerprint.

Cuerpo de respuesta

Campo
Tipo
Descripción

fingerprint

string

La fingerprint generada de la fecha y hora actual.