Módulo 7: Sample Size And Pitfalls

Proyecto: dimensiona el A/B test de recommendations y audita sus trampas

Descripción

Las siete lecciones de este módulo te dieron dos herramientas separadas: calcular cuánta muestra necesitas antes de correr un experimento (lecciones 2-3), y reconocer las cinco trampas que pueden invalidar un resultado incluso con la muestra correcta (lecciones 4-7). Este mini-proyecto te pone a usar las dos, en dos momentos distintos, sobre el mismo caso que acompañó toda la guía: el lanzamiento de recommendations en Mercado.

Parte 1 te pone en el lugar del equipo el día antes de lanzar el experimento: usando sampleSize() exactamente como quedó en la lección 3, vas a calcular cuántos usuarios por variante hacían falta para un MDE de 20% sobre el baseline de 3.2%, y cuántas semanas iba a tomar alcanzar ese número con el tráfico real de Mercado — antes de saber cómo iba a terminar el experimento.

Parte 2 te pone en el lugar de un auditor después de que el experimento terminó: con los resultados reales de los módulos 5 y 6 ya en la mano —control: 12,000/384, variant: 12,000/456, lift +18.75%, p-value ≈ 0.011—, vas a revisar, una por una, si el equipo cayó en alguna de las cinco trampas de este módulo. Vas a encontrar que la mayoría de las verificaciones salen limpias — pero no todas. Esa es, con toda intención, la lección más importante del proyecto: un experimento puede estar bien diseñado en casi todo, y aun así tener un punto débil real que solo aparece cuando lo auditas con rigor.

Conexión con el módulo. Este proyecto no introduce ningún concepto nuevo: reutiliza sampleSize() exactamente como quedó en la lección 3, peekingFalsePositiveRate() como en la lección 4, y simpsonCheck() como en la lección 6, sin ningún cambio, aplicando todo el criterio de las siete lecciones anteriores sobre el caso real de Mercado por primera vez.

Una analogía: la lista de pre-vuelo y la caja negra

Un piloto usa dos listas de verificación completamente distintas, en dos momentos distintos. Antes de despegar, revisa una lista de pre-vuelo: combustible suficiente para la ruta planeada, condiciones climáticas, peso de la carga — todo calculado con anticipación, para un vuelo que todavía no ocurrió. Después de aterrizar —sobre todo si algo salió distinto de lo esperado—, los investigadores revisan la caja negra: qué pasó realmente durante el vuelo, en qué momentos se tomaron decisiones, si algún procedimiento se saltó. Las dos listas existen por la misma razón —volar con seguridad—, pero contestan preguntas distintas: una es sobre lo que vas a necesitar, la otra es sobre lo que de verdad ocurrió.

Este proyecto hace exactamente lo mismo con el experimento de recommendations. La Parte 1 es la lista de pre-vuelo: ¿cuánta muestra vamos a necesitar, calculada antes de saber el resultado? La Parte 2 es la caja negra: ahora que el experimento ya voló y aterrizó, ¿qué pasó realmente en el camino? ¿Alguien se saltó un procedimiento? Ambas verificaciones son necesarias, y ninguna reemplaza a la otra.

Parte 1 — Dimensiona el experimento ANTES de conocer el resultado

Situándote en el momento anterior al lanzamiento, con baseline=3.2% (la tasa de control sin recommendations) y un MDE elegido de 20% —siguiendo la disciplina de la lección 2: el lift más chico que justificaría el costo de mantener el carrusel en producción—, calculamos el tamaño de muestra con sampleSize(), y lo traducimos a semanas usando el tráfico real de Mercado (2,000 usuarios nuevos por semana por variante, el mismo supuesto de la lección 3):

// Reutilizamos sampleSize() EXACTAMENTE como quedo en la leccion 3, sin
// ningun cambio.
function sampleSize({ baseline, mde, alpha = 0.05, power = 0.80 }) {
  const zAlpha2 = 1.96;
  const zBeta = 0.84;
  const p1 = baseline;
  const p2 = baseline * (1 + mde);
  const numerator = Math.pow(zAlpha2 + zBeta, 2) * (p1 * (1 - p1) + p2 * (1 - p2));
  const denominator = Math.pow(p2 - p1, 2);
  return Math.ceil(numerator / denominator);
}

function fmt(n) {
  return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

// ===== Parte 1: dimensionando ANTES de correr el experimento =====
console.log('=== Parte 1: dimensionando ANTES de correr (MDE=20%, baseline=3.2%) ===\n');
const n = sampleSize({ baseline: 0.032, mde: 0.20 });
console.log('n por variante necesario: ' + fmt(n));

const weeklyPerVariant = 2000; // trafico real de Mercado, por variante
const weeksNeeded = Math.ceil(n / weeklyPerVariant);
console.log('trafico disponible: ' + weeklyPerVariant + ' usuarios/semana por variante');
console.log('semanas necesarias: ' + weeksNeeded);

Qué esperar. Al correr el archivo con Node, la salida es exactamente esta:

=== Parte 1: dimensionando ANTES de correr (MDE=20%, baseline=3.2%) ===

n por variante necesario: 12,997
trafico disponible: 2000 usuarios/semana por variante
semanas necesarias: 7

Con esto, antes de haber corrido un solo día del experimento, el equipo hubiera sabido: necesita 12,997 usuarios por variante, y con el tráfico disponible, eso toma 7 semanas. Guarda ese número — la siguiente parte lo compara contra lo que el equipo realmente hizo.

Parte 2 — Audita el experimento REAL en busca de las cinco trampas

Con los resultados reales de los módulos 5 y 6 ya conocidos —control: 12,000/384 (3.20%), variant: 12,000/456 (3.80%), lift +18.75%, corrido durante 6 semanas, p-value ≈ 0.011—, revisamos cada una de las cinco trampas del módulo, una por una.

2a — ¿El tamaño de muestra fue el correcto?

console.log('\n=== Parte 2a: el n real contra el n que hacia falta ===\n');
console.log('n realmente usado: 12,000 por variante, en 6 semanas');
console.log('n que hubiera hecho falta para MDE=20% (el objetivo razonable): ' + fmt(n) + ' (' + weeksNeeded + ' semanas)');

const nForObservedLift = sampleSize({ baseline: 0.032, mde: 0.1875 });
console.log('n que hubiera hecho falta para el lift REAL que se observo (18.75%): ' + fmt(nForObservedLift));
console.log((12000 < nForObservedLift ? '12,000 < ' + fmt(nForObservedLift) : '12,000 >= ' + fmt(nForObservedLift)) +
  '  ->  el experimento corrio con MENOS muestra de la que el efecto real necesitaba');

Qué esperar.

=== Parte 2a: el n real contra el n que hacia falta ===

n realmente usado: 12,000 por variante, en 6 semanas
n que hubiera hecho falta para MDE=20% (el objetivo razonable): 12,997 (7 semanas)
n que hubiera hecho falta para el lift REAL que se observo (18.75%): 14,707
12,000 < 14,707  ->  el experimento corrio con MENOS muestra de la que el efecto real necesitaba

Este es el primer hallazgo real de la auditoría, y no es uno cosmético: el equipo lanzó con 12,000 usuarios por variante en 6 semanas — un poco menos, incluso, de los 12,997 que la Parte 1 recomienda para un MDE de 20% en 7 semanas. Y el lift que terminó apareciendo, 18.75%, hubiera necesitado 14,707 usuarios por variante para un power de 0.80 según la fórmula de la lección 3 — casi 2,700 más de los que el experimento realmente usó. El experimento funcionó —el módulo 6 encontró significancia, con p ≈ 0.011—, pero funcionó con menos muestra de la que un diseño cuidadoso hubiera recomendado para el efecto que terminó apareciendo. No es un error fatal: power=0.80 es una probabilidad, no una garantía, y el equipo tuvo la fortuna de que el efecto real fuera lo bastante grande como para cruzar el umbral de todas formas. Pero es exactamente el tipo de margen estrecho que un cálculo de tamaño de muestra hecho con cuidado, antes de lanzar, hubiera detectado y corregido — con un poco más de muestra o de tiempo, el resultado hubiera sido mucho más robusto, en vez de depender de haber tenido suerte con el tamaño del efecto real.

2b — ¿Hubo peeking?

function peekingFalsePositiveRate(alpha, k) {
  return 1 - Math.pow(1 - alpha, k);
}

console.log('\n=== Parte 2b: chequeo de peeking ===\n');
console.log('El protocolo del modulo 5 establecia analizar el resultado UNA sola vez, en la semana 6.');
console.log('Segun el registro del experimento: el equipo reviso el dashboard de SALUD cada semana');
console.log('(6 miradas, verificando balance y trafico), pero NO tomo ninguna decision de detener');
console.log('el experimento hasta la semana 6, exactamente como establecia el protocolo.');
console.log('\nriesgo SI se hubieran detenido en la primera mirada con p<0.05 (hipotetico, semana 3): ' +
  (peekingFalsePositiveRate(0.05, 3) * 100).toFixed(2) + '%');
console.log('riesgo real asumido por el equipo (una sola decision, al final de la semana 6): 5.00%');

Qué esperar.

=== Parte 2b: chequeo de peeking ===

El protocolo del modulo 5 establecia analizar el resultado UNA sola vez, en la semana 6.
Segun el registro del experimento: el equipo reviso el dashboard de SALUD cada semana
(6 miradas, verificando balance y trafico), pero NO tomo ninguna decision de detener
el experimento hasta la semana 6, exactamente como establecia el protocolo.

riesgo SI se hubieran detenido en la primera mirada con p<0.05 (hipotetico, semana 3): 14.26%
riesgo real asumido por el equipo (una sola decision, al final de la semana 6): 5.00%

Esta verificación sale limpia: revisar el dashboard para confirmar que la asignación seguía balanceada y que no había errores técnicos —el tipo de monitoreo de salud que la lección 4 marca como perfectamente válido— no es lo mismo que peeking. Lo que hubiera convertido esto en peeking es que el equipo hubiera actuado sobre un p-value visto antes de la semana 6 — y el registro del experimento confirma que no lo hizo. El número de 14.26% que calculamos es puramente hipotético: muestra el riesgo al que el equipo se hubiera expuesto si hubiera roto la disciplina, no el riesgo que efectivamente corrió.

2c — ¿Se probaron demasiadas métricas?

Revisando el protocolo escrito en el mini-proyecto del módulo 5: la tabla de protocolo fijó checkoutConversionRate como la única métrica primaria, con H0 y H1 formuladas específicamente sobre ella, antes de correr el experimento. El resultado que decide el experimento —el que reporta el módulo 6— es exactamente esa métrica, sin que el reporte final mezcle ningún hallazgo secundario no pre-registrado como si fuera parte de la conclusión oficial. Esta verificación también sale limpia: no hay evidencia de comparaciones múltiples sin corrección en el resultado que el equipo usó para decidir.

2d — ¿El lift aguanta al segmentar por dispositivo? (chequeo de Simpson)

function simpsonCheck(segments) {
  const totals = { control: { n: 0, conversions: 0 }, variant: { n: 0, conversions: 0 } };
  const bySegment = {};
  for (const [name, seg] of Object.entries(segments)) {
    const controlRate = seg.control.conversions / seg.control.n;
    const variantRate = seg.variant.conversions / seg.variant.n;
    bySegment[name] = { controlRate, variantRate, variantWins: variantRate > controlRate };
    totals.control.n += seg.control.n;
    totals.control.conversions += seg.control.conversions;
    totals.variant.n += seg.variant.n;
    totals.variant.conversions += seg.variant.conversions;
  }
  const aggControlRate = totals.control.conversions / totals.control.n;
  const aggVariantRate = totals.variant.conversions / totals.variant.n;
  const aggregateVariantWins = aggVariantRate > aggControlRate;
  const segmentValues = Object.values(bySegment);
  const allSegmentsAgree = segmentValues.every((s) => s.variantWins === segmentValues[0].variantWins);
  const reversal = allSegmentsAgree && segmentValues[0].variantWins !== aggregateVariantWins;
  return {
    bySegment,
    aggregate: { controlRate: aggControlRate, variantRate: aggVariantRate, variantWins: aggregateVariantWins },
    reversal,
  };
}

// Los datos REALES del experimento (control 12000/384, variant 12000/456),
// desglosados por dispositivo -- confirmando que randomize() (modulo 5)
// mantuvo la MISMA proporcion mobile/desktop en ambos grupos (40% mobile,
// 60% desktop en los dos), sin el confusor ilustrativo de la leccion 6.
console.log('\n=== Parte 2d: chequeo de Simpson sobre los datos REALES, por dispositivo ===\n');
const realExperimentByDevice = {
  mobile: {
    control: { n: 4800, conversions: 120 },
    variant: { n: 4800, conversions: 144 },
  },
  desktop: {
    control: { n: 7200, conversions: 264 },
    variant: { n: 7200, conversions: 312 },
  },
};
const result = simpsonCheck(realExperimentByDevice);
for (const [nm, seg] of Object.entries(result.bySegment)) {
  console.log(nm + ':  control=' + (seg.controlRate * 100).toFixed(2) + '%  variant=' +
    (seg.variantRate * 100).toFixed(2) + '%  variant gana? ' + seg.variantWins);
}
console.log('\nagregado:  control=' + (result.aggregate.controlRate * 100).toFixed(2) + '%  variant=' +
  (result.aggregate.variantRate * 100).toFixed(2) + '%  variant gana? ' + result.aggregate.variantWins);
console.log('reversal detectado (Simpson): ' + result.reversal);

Qué esperar.

=== Parte 2d: chequeo de Simpson sobre los datos REALES, por dispositivo ===

mobile:  control=2.50%  variant=3.00%  variant gana? true
desktop:  control=3.67%  variant=4.33%  variant gana? true

agregado:  control=3.20%  variant=3.80%  variant gana? true
reversal detectado (Simpson): false

Esta verificación también sale limpia, y es la más tranquilizadora de las cuatro: variant gana en mobile (3.00% contra 2.50%), gana en desktop (4.33% contra 3.67%), y gana en el agregado (3.80% contra 3.20%) — sin ninguna reversión. A diferencia del caso ilustrativo de la lección 6, aquí la mezcla de dispositivos es prácticamente idéntica entre control y variant (40% mobile / 60% desktop en ambos), exactamente lo que una aleatorización correctamente implementada —la de la lección 4 del módulo 5— debería producir. El lift de +18.75% no es un artefacto de una mezcla desbalanceada: se sostiene, en la misma dirección, en cada segmento que revisamos.

Leyendo la auditoría completa

De las cuatro verificaciones de la Parte 2, tres salen limpias: no hubo peeking real (el equipo monitoreó salud sin actuar antes de tiempo), no hubo comparaciones múltiples sin corrección (una sola métrica primaria pre-registrada), y no hubo una reversión de Simpson (el lift se sostiene por segmento de dispositivo). Pero la primera verificación —el tamaño de muestra— encontró un punto real y concreto: el experimento corrió con menos muestra (12,000) de la que el efecto que terminó apareciendo (18.75% de lift) hubiera necesitado para un power de 0.80 (14,707). El resultado fue significativo de todas formas —el módulo 6 lo confirma con p ≈ 0.011—, pero ese margen estrecho es exactamente el tipo de riesgo que calcular sampleSize() antes de lanzar, como hiciste en la Parte 1 de este proyecto, hubiera dejado ver con anticipación, en vez de descubrirlo en una auditoría posterior. Un experimento puede pasar la mayoría de las verificaciones de rigor y aun así tener un punto débil real — la disciplina de este módulo no es solo detectar fallas catastróficas, es encontrar exactamente este tipo de margen estrecho antes de que la suerte decida el resultado por ti.

Errores comunes

Dar por buena una auditoría en cuanto la primera verificación sale limpia, sin revisar las demás. Qué pasa: alguien corre el chequeo de Simpson (2d), ve que no hay reversión, y concluye que "el experimento está limpio", sin revisar el tamaño de muestra, el peeking, ni las comparaciones múltiples. Por qué pasa: encontrar una verificación limpia se siente como suficiente evidencia de que todo está bien, sobre todo cuando el resultado agregado ya se veía favorable desde el módulo 5. Cómo detectarlo: el reporte de auditoría solo menciona una o dos de las cinco trampas del módulo, no las cinco. Cómo corregirlo: como en este proyecto, audita las cinco trampas siempre, incluso cuando las primeras salen limpias — precisamente porque, como viste hoy, el punto débil real de este experimento no estaba en la trampa más "dramática" (Simpson) sino en la más discreta (el tamaño de muestra).

Tratar un resultado significativo (p<0.05) como evidencia de que el tamaño de muestra fue el correcto. Qué pasa: alguien argumenta que, como el módulo 6 encontró significancia (p≈0.011), el tamaño de muestra de 12,000 "obviamente fue suficiente" — sin comparar ese número contra lo que sampleSize() calcula para el efecto real observado. Por qué pasa: un resultado significativo se siente como una validación retroactiva de todas las decisiones que llevaron a él, incluyendo el tamaño de muestra. Cómo detectarlo: la justificación de que "el n fue suficiente" cita únicamente el p-value final, sin ningún cálculo de sampleSize() de respaldo. Cómo corregirlo: como muestra la Parte 2a de este proyecto, un resultado significativo con una muestra menor a la recomendada no es evidencia de que el diseño fue el correcto — es, con más frecuencia de la que parece, el resultado de haber tenido suerte con el tamaño del efecto real. La única forma de saber si el n fue el correcto es comparar contra sampleSize(), calculado con el MDE que el equipo se había propuesto, no con el lift que casualmente terminó apareciendo.

Confundir "revisar el dashboard" con "hacer peeking", penalizando cualquier monitoreo durante el experimento. Qué pasa: después de aprender sobre el peeking en la lección 4, alguien concluye que revisar el experimento en absoluto antes del final es siempre incorrecto, incluyendo verificaciones básicas de salud como el balance de la asignación. Por qué pasa: la lección 4 advierte fuertemente contra el peeking, y sin la distinción precisa que la Parte 2b de este proyecto hace explícita, es fácil sobre-corregir hacia "nunca mires nada hasta el final". Cómo detectarlo: el equipo evita revisar el experimento en absoluto durante su ejecución, incluso para detectar errores técnicos obvios (como un bug que rompiera la instrumentación a mitad de camino). Cómo corregirlo: como confirma la Parte 2b, el peeking es específicamente sobre actuar —detener el experimento— basándose en un p-value visto antes de tiempo. Monitorear la salud operativa (balance, volumen de tráfico, errores técnicos) sin tomar esa decisión es exactamente lo que el equipo de recommendations hizo bien, y es una práctica recomendada, no una trampa.

Ejercicios

Ejercicio 1 — Recalcula la Parte 1 con un MDE distinto. Si el equipo hubiera fijado un MDE de 10% en vez de 20% (una decisión más exigente, según el criterio de la lección 2), ¿cuántos usuarios por variante hubieran hecho falta, y cuántas semanas, con el mismo tráfico de 2,000 usuarios por variante por semana?

Ver solución

sampleSize({ baseline: 0.032, mde: 0.10 }) da 49,718 usuarios por variante (el mismo número de la tabla de la lección 3). Con 2,000 usuarios por variante por semana, eso toma Math.ceil(49718 / 2000) = 25 semanas — casi seis meses, muy por encima de las 6-7 semanas que tomó el experimento real con MDE=20%. Este ejercicio ilustra, una vez más, el costo cuadrático de reducir el MDE que viste en la lección 3: apenas duplicar la exigencia de sensibilidad (de 20% a 10%) casi cuadruplica tanto la muestra como el tiempo necesario.

Ejercicio 2 — Interpreta el hallazgo de la Parte 2a. Un compañero de equipo argumenta: "Si el resultado fue significativo con 12,000 usuarios, entonces 12,000 era suficiente — no entiendo por qué la auditoría lo marca como un problema." ¿Cómo le explicarías el error en ese razonamiento, usando los números concretos de este proyecto?

Ver solución

El error es confundir "funcionó esta vez" con "estaba bien dimensionado" — exactamente el segundo error común de esta lección. Power=0.80 significa que, si el efecto real tiene el tamaño del MDE, el experimento lo detecta el 80% de las veces — no el 100%. Con 12,000 usuarios por variante frente a los 14,707 que sampleSize() recomienda para un efecto del 18.75%, el experimento tenía, en la práctica, un power efectivo menor al 80% declarado para ese tamaño de efecto específico — el equipo tuvo la fortuna de que el resultado cruzara el umbral de todas formas (p≈0.011, no un valor extremadamente bajo), pero un experimento idéntico, corrido de nuevo con el mismo efecto real, podría perfectamente no haber alcanzado significancia con esa misma muestra. Un resultado significativo con una muestra insuficiente no es una prueba de que la muestra era suficiente — es, con frecuencia, el resultado de un margen estrecho que salió bien esta vez.

Ejercicio 3 — Diseña el reporte final de la auditoría. Basándote en las cuatro verificaciones de la Parte 2, redacta en 3-4 frases el resumen ejecutivo que presentarías al equipo de Mercado sobre la calidad del experimento de recommendations, incluyendo tanto lo que salió bien como el hallazgo real.

Ver solución

Un resumen razonable: "El experimento de recommendations pasa tres de las cuatro verificaciones de rigor sin observaciones: no hubo peeking (el monitoreo de salud nunca se usó para detener el experimento antes de tiempo), no hubo comparaciones múltiples sin corrección (una sola métrica primaria pre-registrada), y el lift se sostiene consistentemente al segmentar por dispositivo (sin reversión de Simpson). Sin embargo, el tamaño de muestra usado (12,000 por variante) quedó por debajo del recomendado tanto para el MDE objetivo de 20% (12,997) como, más notablemente, para el efecto que terminó apareciendo (18.75%, que hubiera requerido 14,707). El resultado fue significativo de todas formas, pero con un margen más estrecho del ideal — para futuros experimentos de tamaño y efecto similares, recomendamos calcular sampleSize() antes de fijar la duración, con al menos el margen que este caso reveló como necesario." El reporte reconoce lo que funcionó sin exagerar el hallazgo, y lo convierte en una recomendación concreta para el futuro — exactamente el espíritu de una auditoría útil.

Resumen y siguiente paso

En este mini-proyecto dimensionaste el A/B test de recommendations antes de conocer su resultado —12,997 usuarios por variante, 7 semanas, para un MDE de 20% sobre un baseline de 3.2%— y después auditaste el experimento real de los módulos 5 y 6 contra las cinco trampas de este módulo. Tres verificaciones salieron limpias: sin peeking real, sin comparaciones múltiples sin corregir, y sin reversión de Simpson al segmentar por dispositivo. Pero encontraste un hallazgo genuino: el experimento corrió con menos muestra (12,000) de la que el efecto observado (18.75%) hubiera necesitado para un power de 0.80 (14,707) — un margen estrecho que funcionó, pero que un cálculo de tamaño de muestra hecho por adelantado hubiera identificado antes de correr un solo día del experimento.

Con esto cierras el módulo 7: sabes, de punta a punta, cuánta muestra necesita un experimento antes de lanzarlo, y sabes auditar un resultado ya obtenido contra las cinco trampas más comunes que pueden hacerlo parecer más — o menos — confiable de lo que realmente es. Y, sobre todo, viste que estas dos disciplinas no son un ejercicio teórico: aplicadas al caso real de esta guía, revelaron un punto débil genuino que ni el módulo 5 ni el módulo 6 habían señalado.

Hacia dónde sigues. El módulo 8, el capstone de toda la guía, te pone a medir el lanzamiento completo de recommendations de punta a punta —el funnel (módulo 2), la retención por cohortes (módulo 3), la North Star y sus guardrails (módulo 4), el diseño del A/B test (módulo 5), el tamaño de muestra y esta misma auditoría de trampas (módulo 7), y la significancia estadística (módulo 6)— y a decidir, con toda esa evidencia junta, si recommendations se envía, se revierte, o se itera. Y, más allá de esta guía, la mecánica de ese envío —el rollout gradual, los feature flags, el canary release— es exactamente donde continúa shipping-and-iterating-products-guide.

Recursos

  • Ron Kohavi, Diane Tang y Ya Xu, Trustworthy Online Controlled Experiments: A Practical Guide to A/B Testingexperimentguide.com. El mismo recurso citado en cada lección del módulo: revísalo de nuevo ahora que aplicaste el cálculo de tamaño de muestra y la auditoría completa de trampas sobre un caso de punta a punta. En inglés.
  • Evan Miller, Sample Size Calculator (Evan's Awesome A/B Tools) — evanmiller.org/ab-testing/sample-size.html. Úsalo para confirmar de forma independiente los números de la Parte 1 de este proyecto, y para explorar cómo hubiera cambiado el plan del equipo con un power o un alpha distintos. En inglés.
  • Wikipedia, "Simpson's paradox" — en.wikipedia.org/wiki/Simpson's_paradox. Revísalo una última vez ahora que aplicaste simpsonCheck() a un caso real donde la verificación salió limpia — un recordatorio de que la ausencia de una reversión es, en sí misma, una confirmación valiosa de que la aleatorización funcionó como se esperaba. En inglés.