Skip to main content
The Operator Log
Operator2026-05-11· 8 min read

Calibrating ROAS thresholds to your store, not the internet.

The 'ROAS > 2.0' rule of thumb is an internet artifact. Your winner floor lives in your own distribution. Here's how the classifier finds it.

Jacob Dorian

Guest · Solace

Every founder has heard it: 'keep ROAS above 2.0 and you're fine.' It's a number someone said on a podcast in 2019, and it has nothing to do with your margins, your AOV, or your repeat rate. We run Solace on Magistry, and the single biggest unlock was killing the universal threshold and letting the classifier find ours.

Why a fixed floor is the wrong tool

A 2.0 ROAS on a 70%-margin candle is a different business than a 2.0 ROAS on a 28%-margin apparel SKU with a 4% return rate. A fixed floor treats them the same. Worse, it ignores the part of paid that actually pays: the second and third order. If your contribution margin and repeat behavior aren't in the equation, you're optimizing the wrong number with great discipline.

What the classifier actually looks at

Magistry doesn't apply a constant. It builds a winner floor from your own distribution and then gates scaling decisions against it. The inputs are boring on purpose:

  • Contribution margin per SKU, not blended gross margin.
  • Blended ROAS across a rolling window, so one good day doesn't trip a scale.
  • New-customer vs. returning split — a campaign acquiring repeat buyers gets a different floor than one buying first orders.
  • Return and refund rate, netted out before the decision, not after.
ad_decision_log — scale gated on a store-specific floorjson
{
  "action": "SCALE_BUDGET",
  "campaign": "meta/advantage+/spring",
  "blended_roas_7d": 2.41,
  "winner_floor": 2.18,
  "contribution_margin": 0.52,
  "nc_share": 0.63,
  "decision": "approved",
  "reverse_op": "SET_BUDGET 920.00"
}

The floor here is 2.18, not 2.0, and it moved up because this campaign skews toward first orders that haven't paid back yet. A blanket 2.0 rule would have scaled into a loss that looks like a win for six weeks.

We stopped arguing about whether 2.0 was the right number and started reading the number our own store was telling us. The arguments went away.

Jacob Dorian, Solace

How to set yours

Start in dry-run. Let the classifier propose a floor and watch the rows it would have written for two weeks against what you actually did. You'll find the floor is usually higher than the rule of thumb on acquisition-heavy campaigns and lower on retention-heavy ones. When the proposed rows stop surprising you, flip to live. The threshold isn't a setting you guess once — it's a row the system keeps honest.

// reading this?

Reading this? You'd like the product.

If the writing resonates, the product probably will too. Same bar, same prose, same refusal to ship something you can't reverse.

Dry-run by default · Append-only logs · One-click rollback