AI Engineering
/
AI Product & Experimentation
/

Design an A/B test with cost guardrails

AI Product & Experimentation · 2 to 3 hours

Design an A/B test with cost guardrails

Write the experiment contract and sample-size plan for a staged-hints A/B test, implement a validated per-arm summary of outcomes and costs, and explain which checks and guardrails must pass before a lift can justify shipping.

Medium
Hands-on

3 h

Used in interview rounds:

Live Coding (Medium)

Step 1: The question

Write the experiment contract for the staged-hints test, including the sample size and how long the test must run. Implement the per-arm summary so it validates one outcome and cost record per assigned learner and reproduces fixtures A and B. Then explain the data checks, uncertainty estimates, and quality and cost guardrails that must pass before the lift can support a ship decision, and review the teammate's draft analysis plan.

The staged-hints test

Suppose a coding-practice platform answers a hint request with one full explanation from a language model it calls. The team has built staged hints on the same model: a nudge, then a targeted hint, then one worked step. They want to know whether staged hints help learners solve problems on their own without raising cost or answer disclosure beyond agreed limits. All figures are synthetic.

Planning inputValue
Eligible learnersSigned-in learners who start a supported beginner exercise
TrafficAbout 4,000 newly eligible learners per week
Allocation50% control (full explanation), 50% treatment (staged hints)
Primary outcomeSolves a related exercise without hints within 7 days of assignment
BaselineAbout 20% of eligible learners reach the primary outcome
Smallest effect worth acting on+2 percentage points on the primary outcome
Significance and power0.05 two-sided, 80% power
Cost guardrailMean model cost per assigned learner at most 25% above control
Quality guardrailShare of sampled hints judged incorrect in blinded review at most 1 percentage point above control
Not set yetTolerances for full-answer disclosure and hint latency

Model cost is recorded per learner in integer microunits (millionths) of one declared currency, including retries, escalations, and failed attempts.

Write the experiment contract

Write the contract before launch: hypothesis, eligibility, assignment unit, variants, primary outcome, guardrails with tolerances, observation window, statistical method, stopping rules, and decision owner. The smallest effect worth acting on sets the sample size and separates a real but trivial change from a useful one.

Randomize before the treatment can influence who is included, and keep each learner's assignment stable across sessions and devices.

Version the model, prompt, retrieval policy, and UI. If the treatment bundles several changes, the experiment estimates the bundle's effect and cannot isolate each part without additional design.

Summarize one record per assigned learner

The function takes one row per assigned learner whose observation window has closed. success is true when the primary outcome occurred within the window. A learner who never came back has an observed outcome of false once the window closes; one whose events were lost, or whose window is still open, has a missing outcome, which is resolved upstream and never coded as false.

costMicrounits is the learner's total attributable model cost as an integer, including retries and failed attempts, and 0 for a learner who never asked for a hint. Integers avoid floating-point drift in currency totals.

type UserRecord = {
  userId: string;
  variant: "control" | "treatment";
  success: boolean;
  costMicrounits: number;
};

type ArmSummary = {
  users: number;
  successRate: number; // successes / users
  meanCostMicrounits: number; // total cost / users
  costPerSuccessMicrounits: number | null; // total cost / successes, null with 0 successes
};

declare function summarizeVariants(rows: UserRecord[]): {
  control: ArmSummary;
  treatment: ArmSummary;
  absoluteLiftPercentagePoints: number; // 100 * (treatment rate - control rate)
  relativeLift: number | null; // (treatment rate - control rate) / control rate, null when the control rate is 0
};

Python uses summarize_variants(rows) and snake_case keys (user_id, cost_microunits, success_rate, and so on).

Validate in this order and stop at the first failure (JavaScript throws an Error, Python raises ValueError):

OrderCheckMessage
1rows is a non-empty listExpected nonempty user records
2Each row is an object (a dict in Python)Record must be an object
3The user ID is a non-blank string not seen in either armMissing or duplicate user ID
4The variant is exactly control or treatmentUnknown variant
5success is a booleanOutcome must be observed boolean
6The cost is an integer of at least 0, not a booleanCost must be nonnegative integer
7After all rows, each arm has a learnerBoth variants need observations

Two fixtures, each listing user (success, cost in microunits), exercise the function:

FixtureControlTreatment
Au1 (true, 100), u2 (false, 300)u3 (true, 250), u4 (true, 350)
Bu5 (false, 100), u6 (false, 100)u7 (true, 200), u8 (false, 0)

IDs are compared exactly as given (no trimming or case folding), and keys outside the record are ignored.

Four learners per fixture check arithmetic and validation only, not whether staged hints work.

Planning formula from the guide: n per arm = (z_alpha + z_power)^2 * (p_c * (1 - p_c) + p_t * (1 - p_t)) / d^2, where p_c is the baseline rate, d the smallest difference worth acting on, p_t = p_c + d, z_alpha = 1.96 (two-sided 0.05), and z_power = 0.84 (80% power).

Constraints

  • Analyze learners by assigned arm (intent to treat), with one record per assigned learner
  • Never code a missing outcome as false
  • Costs are integer microunits per assigned learner, including retries and failed attempts
  • Report a ratio whose denominator is 0 as null
  • Use the scenario's planning inputs and tolerances, and propose the ones it leaves unset

Deliverables

  • An experiment contract with every field filled, including the tolerances you propose
  • The data and event checks that run before analysis, and what each failure blocks
  • A summary function that passes the linked practice problem, with your fixture A and B results
  • Sample size per arm, test duration, and the intervals you would report
  • A decision rule that combines data validity, the primary effect, and every guardrail

Step 2: Hints

Optional. Each hint gives a little more away.

Step 3: Work through it

Code exercise

Per-arm outcome and cost summary

Implement summarizeVariants(rows) (Python summarize_variants(rows)) from the contract above. Run the seven checks in order and raise the first failing message, then return each arm's users, success rate, mean cost, and cost per success, plus the absolute and relative lift, with null (None in Python) wherever a denominator is 0.

Expected

The practice problem's tests compare the whole summary for fixtures A and B, check validation messages for invalid input such as duplicate or blank IDs, a capitalized variant, non-boolean outcomes, boolean, negative, or fractional costs, and a missing arm, and check that a ratio with a zero denominator comes back as null rather than 0, NaN, or Infinity. Floating-point results are compared after rounding to four decimal places.

Open coding workspace

Limitations

The function summarizes pre-aggregated, mature records for one experiment. It does not randomize, join events to assignments, impute missing outcomes, test sample ratio mismatch, estimate intervals or p-values, or make a ship decision. Python accepts only int costs while JavaScript cannot tell 100.0 from 100, so the fixtures use whole numbers. A production schema also scopes identity to the experiment and checks assignment consistency against the source registry.

Predict the outcome

Predict both summaries

Compute every output for fixtures A and B by hand, writing each ratio as a fraction first, before you reveal the answers. Costs are in microunits.

OutputFixture AFixture B
Control users??
Control success rate??
Control mean cost??
Control cost per success??
Treatment users??
Treatment success rate??
Treatment mean cost??
Treatment cost per success??
Absolute lift (percentage points)??
Relative lift??

Diagnose

Review a draft analysis plan

A teammate drafts the analysis for the staged-hints test:

  1. Build the analysis table from hint-request logs, one row per request, using the variant label the browser sends with each request.
  2. In treatment, include only learners whose staged hints loaded without an error.
  3. Give learners with no outcome event success: false.
  4. Sum cost from successful model responses only.
  5. Check the dashboard every morning and stop as soon as the primary lift is significant at 0.05.
  6. If the primary outcome does not move, report whichever of 20 learner segments improved most as the result.
  1. For each step, name the bias or error it introduces.
  2. Rewrite the step so the analysis stays valid.
  3. Say which corrections the summary function's contract already enforces and which must happen upstream or in the analysis plan.

Kept in this browser. Saving your score below keeps a copy with it.

0 / 5000

Step 4: Reference answer

Step 5: Score yourself

Score each dimension 0, 1, or 2, then save the score to your history. Readiness thresholds are editorial estimates.

Grades your written answer against this rubric with your own AI provider key from Settings. It is a second opinion: the score you save is still yours.

Experiment contract

What earns a 2: Fills every contract field from the scenario, proposes the missing tolerances, and fixes them before any result is seen.

Event and data integrity

What earns a 2: Names the pre-analysis checks (assignment join, event deduplication, one assignment per learner, sample ratio, missingness per arm) and what each failure blocks.

Implementation

What earns a 2: Passes the linked practice problem, validates in the stated order, and shows the fixture A and B arithmetic as fractions.

Statistical reasoning

What earns a 2: Shows the sample-size and duration arithmetic from the scenario's inputs, analyzes at the learner level, and reports intervals instead of a bare lift.

Decision quality

What earns a 2: States a decision rule fixed in advance that reads data validity, the primary interval, and every guardrail bound, and names the action for each outcome.

0 of 10 · Scored 0 of 5 dimensions

Ready at 8 of 10, with no 0 in Event and data integrity or Implementation or Statistical reasoning

Kept in this browser until you sign up, then it moves to your account.

Complete this level when another engineer can reproduce your fixture summaries from the contract alone and you can name the evidence still missing before a ship decision.

Your saved scores

Practice saves and mock interview answers on this question, newest first.

No saved scores yet. Score every dimension, then save.

Step 6: Follow-up questions

An interviewer may ask these next.

Why analyze assigned learners rather than only successful requests?

What does a sample ratio mismatch indicate?

Why does the aggregation level matter?

Does the summary function prove that the treatment works?

Why predefine a harm tolerance for each guardrail?

Step 7: Mark complete