---
name: run-creative-testing-framework
description: >-
  Runs Meta creative through a hypothesis-led testing cycle: a standing campaign splits each hypothesis into
  ABO cells with equal budget per creative for a clean read, or a Dynamic Creative ad set for broad
  exploration rather than one clean variable. Changes exactly ONE variable per test - concept, hook, or
  format - and withholds judgment until each cell clears the ~50-event/7-day learning phase plus enough
  spend to be non-noisy. Ranks cells on cost per result (not CTR or hook rate), kills cells far worse than
  the control, and graduates the survivor into a scaling plan. Reach for it when launching a new concept
  batch, when an account has no test cadence, or when a creative call is made off day-2 CTR not a settled
  cost per result. It ends at ranked creatives plus a documented winner - it does not manage fatigue timing
  (diagnose-creative-fatigue), build Dynamic Creative mechanics (set-up-dynamic-creative), or scale past the
  test cell (scale-horizontally-with-duplication).
---
# Run a Meta Creative Testing Framework

## Purpose
Most Meta creative "testing" is actually guessing with extra steps: variants get shipped with no
stated hypothesis, judged on day-2 CTR, and killed before the ad set even clears learning. This
skill runs every creative decision through a standing, disciplined cycle, one hypothesis, one
variable, equal-budget cells, a judging floor tied to Meta's own learning phase, and a primary
metric (cost per result) that survives contact with the finance team.

## When to run
- Launching a new batch of creative concepts into an active or standing testing campaign.
- The account has no standing test cadence, ad sets accumulate spend with no structured comparison.
- A creative decision is being made off early CTR/hook rate before any cell has cleared learning.
- A previous winner needs to be re-validated against a fresh round of challengers.

## When NOT to run
- The question is why a creative that WAS winning is now declining, `diagnose-creative-fatigue`.
- The need is broad combinatorial exploration with limited production, not a clean read, build the
  feed in `set-up-dynamic-creative` (it can still be routed through this skill's cadence as one cell).
- Scaling an already-declared winner into new budget or audiences, `scale-horizontally-with-duplication`.
- No finished creative exists yet to test, `produce-ugc-creative-brief` first.

## Prerequisites
- A standing testing campaign with its objective already set (`select-campaign-objective`) and
  tracking verified.
- At least two finished creative assets per hypothesis.
- A primary metric (cost per result) and a kill threshold agreed with the user before launch.
- Budget sized so each cell can plausibly clear ~50 optimization events in 7 days, undersized cells
  never exit learning and produce unusable comparisons.

## Procedure
1. **Write one hypothesis per test.** State it as "if we change X (concept, hook, or format) then
   metric Y should move because Z." Isolate exactly one variable, never bundle a new hook with a
   new format in the same cell.
2. **Choose the mechanism.** Default to ABO discrete cells for a clean single-variable read. Route
   to `set-up-dynamic-creative` instead only when the goal is broad early exploration and per-cell
   attribution isn't required (see Decision rules).
3. **Size the cells for parity.** Same `daily_budget` on every cell (money in the account's minor
   unit, a $50/day cell is `daily_budget=5000`), same audience, placement, and bid setup across
   cells, so creative is the only thing that differs.
4. **Build each cell.** `mads_create_creative` for the creative object, `mads_create_adset`
   (status PAUSED) with the matched budget/targeting, `mads_create_ad` (status PAUSED) referencing
   the creative. Run `mads_preview_creative` on every creative before it goes further.
5. **Summarize and get approval.** Plain-English recap of each cell, hypothesis, what changes,
   budget, for explicit user approval; commit only after approval.
6. **Launch and hold the freeze.** Audience, bid, budget, and landing page stay fixed for the test
   window; creative is the only variable in motion.
7. **Monitor without judging early.** Track spend and impressions per cell; do not compare cost per
   result until each cell has cleared roughly 50 optimization events in 7 days, early CTR is noise.
8. **Apply the kill rule.** A cell running materially worse than the control (see Decision rules)
   after clearing learning gets `mads_update_ad` (status=PAUSED) and logged as a rejected hypothesis.
9. **Rank at the gate.** Pull results with `mads_run_insights` + `mads_get_insights`
   (or `mads_get_insights` for a quick single pull) for spend, results, cost per result, CTR,
   and hook rate per cell. Rank primarily on cost per result; treat CTR/hook rate as diagnostic.
10. **Declare and log.** Record the winner, the rejected hypotheses, and why. Hand the winner to
    `scale-horizontally-with-duplication` and feed each loss into the next hypothesis backlog.

## Decision rules
- **ABO vs DCO:** need a clean, single-variable read → ABO cells; broad early exploration across
  many combinations with no need for per-combination attribution → `set-up-dynamic-creative`.
- **Judging floor:** never rank or kill a cell before it clears roughly 50 optimization events per
  ad set per 7 days and has accumulated meaningful spend, the same gate as any Meta ad set.
- **Primary metric:** cost per result ranks the cells; CTR, hook rate, and hold rate diagnose but
  never rank, a high-CTR loser with a worse cost per result is still a loser.
- **Kill threshold:** a cell running roughly 50%+ worse in cost per result than the control, after
  clearing learning, gets paused; milder gaps wait for the full data gate before any call is made.
- **One variable, no exceptions:** if two things changed between cells, the result is unusable, invalidate it and rerun clean rather than trying to interpret a confounded test.
- **Budget parity is load-bearing:** unequal cell budgets skew delivery toward whichever the auction
  already favors, contaminating the read before it starts.
- **Done means:** every cell cleared the learning/spend gate, cost-per-result ranking is recorded,
  the winner and rejected hypotheses are logged, and a next hypothesis is queued.

## Common failure modes
- **Declaring a winner off day-2 CTR** before any cell has cleared learning.
- **Confounded cells**, two variables changed at once, so the result can't be attributed to either.
- **Uneven cell budgets** skewing delivery toward one creative regardless of underlying quality.
- **Testing with no kill rule**, so the standing campaign fills with dead weight nobody prunes.
- **Ranking by CTR or hook rate instead of cost per result**, a scroll-stopping hook that doesn't
  convert is still a loss.
- **No hypothesis written down**, a variant ships, wins or loses, and nobody can explain why.

## Related skills
- Before: `produce-ugc-creative-brief` (supplies the assets to test), `select-campaign-objective`
  (sets the optimization event the test measures against).
- After: `scale-horizontally-with-duplication` (scaling domain) for confirmed winners.
- Related: `set-up-dynamic-creative` (the DCO alternative for early, broad exploration),
  `diagnose-creative-fatigue` (what happens once a winner's performance later declines),
  `improve-hook-rate-and-hold` (deepens the hook/hold read used inside this cycle).
