act · campaigns
Stop rules and readouts
When a campaign ends and how it's judged.
In Campaigns
Every campaign ends one of three ways: its window runs out, a stop rule fires, or the founder stops it. Whichever way, it ends in a readout written on a date set at launch. This page covers the kinds of stop rule, what gets checked live, daily and only at the readout, twelve ready stop rules, and the readout row every campaign leaves behind.
campaign library → segment · who → offer · what they get → arms · who gets what → stop and readout · when it ends
Guardrails live, goals at the readout — Stop requests and removals are watched all the time. The goal metric is judged once, on the date.
Every stop rule has a minimum sample — "0 joins" means nothing after 3 offers. Write the count into the rule.
A readout even when it fails — Losses are half the learnings. The row gets written whatever happened.
in industry terms
Stop rules are pre-registered; the readout is the result, judged once.
Experiment teams call these futility boundaries, guardrail metrics and pre-registration. The idea is the same: decide what failure and success look like before the first message, so the result can't be argued into a win afterwards.
ends it early — Futility · Enough tries with nothing to show. Change something and start a new campaign.
ends it now — Guardrail · Something must not get worse: stop requests, removals, founder time.
ends it on time — Window and readout · The default. The result is read on the readout date, against the win rule.
how it works
The check schedule, from launch to the next campaign.
Three clocks run at once. Guardrails are checked live, futility daily, the goal only at the readout.
- Launch — rules frozen
- Live — guardrails
- Daily — futility rules
- Window ends — or stop fires
- Readout — win rule
- Decision — repeat, change, retire breach
- Pause — guardrail hit fires
- Stop early — futility the readout's learning sets the next campaign's defaults
| Check | How often | What it can do |
|---|---|---|
| Guardrails (stop requests, removals, account status) | live, on every event | pause the campaign immediately |
| Futility rules | once a day, after the minimum sample | stop early and record why |
| Budgets (minutes, tool spend) | daily and weekly | pause or shrink the segment |
| Goal metric vs win rule | once, on the readout date | decide: repeat, change one thing, retire |
| Pre-set early win | weekly, only if written at launch | ship early with the reason logged |
the object
The stop rule, and the readout row.
The stop rule lives on the campaign; the readout is one row in the campaign log.
| Field | Type | What it holds |
|---|---|---|
stop_rule.kind | enum | futility · guardrail · window · exhausted · success_preset · external · manual |
stop_rule.metric | metric id | The metric it watches, defined once in Metric definitions. |
stop_rule.condition | expression | The test, e.g. offers_made >= 40 and joins = 0. |
stop_rule.min_n | integer | The count below which it never fires. |
readout.date | date | Set at launch. Not moved. |
readout.per_arm | table | Counts at each rung, per arm, and the goal metric. |
readout.lift | number + interval | Treatment over holdout, with how sure. |
readout.decision | enum | repeat · change_one · retire |
readout.learning | text | One sentence, written for the next campaign. |
one record, as data
{
"campaign_id": "camp.lead-to-waitlist.2026-10-20",
"stop_rules": [
{
"kind": "futility",
"metric": "joins",
"condition": "offers_made >= 40 and joins == 0",
"min_n": 40
},
{
"kind": "guardrail",
"metric": "stop_requests_per_100",
"condition": ">= 2",
"min_n": 50
}
],
"readout": {
"date": "2026-11-17",
"per_arm": {
"treatment": {
"offers": null,
"joins": null
},
"holdout": {
"joins": null
}
},
"lift": null,
"decision": null,
"learning": null
}
}the catalog
Twelve stop rules, by kind.
Futility rules end a campaign that isn't working; guardrails protect people and the founder; time rules end it on schedule; a success rule is only allowed when written at launch.
stop.futility-count — Futility
Futility by count
Enough tries with nothing to show for it.
- rule
offers_made >= 40 and joins = 0- checked
- daily
- then
- change the offer, not the queue
stop.futility-rate — Futility
Futility by rate
A rate stays under a floor after a minimum sample.
- rule
touches >= 50 and reply_rate < 0.02- checked
- daily after min sample
- then
- change the segment or the opener
stop.engagement-floor — Futility
Engagement floor
Public plays that draw no attention.
- rule
answers >= 20 and profile_visits < 2- checked
- daily
- then
- wrong communities: swap them
stop.stop-requests — Guardrail
Stop requests
People asking you to stop is the first guardrail.
- rule
stop_requests per 100 touches >= 2- checked
- live
- then
- pause, read the replies, fix the sequence
stop.removals — Guardrail
Removals and reports
Comments removed or accounts reported on a platform.
- rule
removed_or_reported >= 1 in a community- checked
- live
- then
- stop in that community; re-read its rules
stop.founder-time — Guardrail
Founder time budget
The campaign is eating the week.
- rule
founder_minutes_week > budget- checked
- weekly
- then
- cut steps or the segment
stop.credits — Guardrail
Credit budget
Drafting and enrichment cost more than planned.
- rule
credits_spent > budget- checked
- daily
- then
- pause; check cost per join
stop.window — Time
Window end
The default: the campaign ends on its end date.
- rule
today > window.end- checked
- daily
- then
- read out on the readout date
stop.segment-exhausted — Time
Segment exhausted
Everyone in the frozen list has finished the sequence.
- rule
members_active = 0- checked
- daily
- then
- read out early, at the end of the outcome window
stop.success-preset — Success
Early win, pre-set only
Stopping early for success is allowed only with a rule set at launch and a minimum sample.
- rule
per_arm_n >= 150 and lift > 2x and holdout_n >= 30- checked
- weekly
- then
- ship the winner; log it as an early stop
stop.platform — External
Platform or account trouble
A ban, a rate limit wall, or a needs-reconnect account.
- rule
account.status != active- checked
- live
- then
- pause; nothing sends from a broken account
stop.manual — External
Stopped by hand
The founder ends it. Allowed, but the reason is required.
- rule
- founder action
- checked
- any time
- then
- log the reason; still write the readout
illustrative example
Lead to waitlist: its rules and its readout.
From the campaign preset and the sample campaign on the Campaign library page.
futility — offers_made >= 40 and joins = 0: change the offer, not the queue
guardrails — stop requests per 100 touches, founder minutes per week
readout
first readout Nov 17, 2026; weekly after that in the Monday report
The readout date in the sample campaign.
win rule — joins per offer of at least 10%, and above the holdout
failure modes
What goes wrong, and how to catch it.
How each one shows up, and the check that catches it before it costs a week.
| Failure | How it shows up | How to catch it |
|---|---|---|
| No minimum sample | Campaign killed after 5 offers | Every futility rule carries min_n |
| Moving goalposts | Win rule rewritten after seeing the data | Rules frozen at launch; edits start a new campaign |
| Stopping on noise | A good week reads as a win | Goal metric judged only on the readout date |
| Forgotten readout | Campaign ran out, nothing written | Readout date on the calendar at launch; the Monday report lists overdue readouts |
| Silent pause | A guardrail paused it and nobody noticed | Every pause is an event and appears in the daily snapshot |
data to capture
Record it so a model can learn from it later.
Follows the guide's eight data-spine rules: log the decision, version what decided, freeze the inputs, keep the negatives, log the odds, treat every human touch as a label, keep one chain of ids, keep the raw.
record
- the stop rules and win rule as frozen at launch
- every check: which rule, the value it saw, pass or fire
- the stop reason and the counts at that moment
- the readout row: per-arm funnel, lift, decision, learning
label
decision outcomes: did a "change one thing" campaign beat the one before it
trains
priors for the next campaign's defaults, and better futility thresholds per playbook
test
futility thresholds and window lengths · tracked as learnings; compared across campaigns