phase 4 · learn
Improvement loop
Go deeper
Every number the pipeline records gets a line it shouldn't cross. When a metric crosses its line, the loop fires: it diagnoses which part broke, writes one hypothesis, and hands a test to the Experimentation engine. The decision comes back and the baseline moves, and the line itself gets re-fitted. Analysis stops being something you remember to do on Sundays and becomes a system that tells you where to look.
funnel → metrics → thresholds · triggers · actions → experimentation engine → learnings → back to every stage
what it is, in industry terms
Monitoring, alerting and a closed improvement loop.
Ops teams call the first half monitoring and alerting: a metric, a threshold, an alert. Quality engineers call the statistical version statistical process control: draw control limits from the metric's own history, and only act when a point falls outside them. Growth teams call the second half the improvement loop or build, measure, learn. This page joins the two halves, so that an alert can't just sit in a channel. Each firing either fixes something, opens a test, or gets labeled a false alarm, and the threshold learns from that label.
what it is for
- Catch breakage fast. A source stops, a detector floods, a campaign draws stop requests. Guardrails act within minutes, without waiting for anyone.
- Find the constraint. Control limits on each funnel rung show which step got worse for real, not by noise.
- Learn the thresholds themselves. Every firing is labeled real or false alarm, so the lines get sharper over time.
what it is not
- Not a dashboard. Dashboards wait to be read. Thresholds come to you.
- Not auto-shipping. The loop can pause, shadow and queue offline replays on its own. Any live change to what a lead or a follower sees goes through the founder.
- Not a reaction to every dip. Minimum-sample gates and control limits keep a quiet Tuesday from opening a test.
how it works
Eight steps, one loop.
The loop has no start. The daily snapshot measures, every threshold compares, a crossing triggers. Each step writes a row, so the loop can be replayed and audited.
- 1 · system — Measure daily snapshot
- 2 · system — Compare to the threshold
- 3 · system — Trigger alert + action
- 4 · agent — Diagnose which part broke
- 5 · agent · founder — Hypothesis one change
- 6 · engine — Test replay, shadow or A/B
- 7 · founder — Decide ship · revert · extend
- 8 · system — Update baseline + threshold EVERY ROW VERSIONED, EVERY FIRING LABELED the loop runs on its own cadence: live, daily, Monday
Measure — The daily snapshot counts every rung, trigger, detector, play and campaign, plus the live event stream for guardrails.
Compare — Each active threshold reads its metric over its window. Below the minimum sample, it does nothing.
Trigger — A crossing writes an alert row and runs the threshold's action, unless the same threshold fired inside its cooldown.
Diagnose — The improvement agent pulls the slice behind the number: which detector, which play, which day, which version changed.
Hypothesis — One change, written into the hypothesis registry with the alert attached as evidence and an expected effect.
Test — Listen-side changes replay offline or run in shadow. Act-side changes get a randomized test with a holdout.
Decide — The readout applies the win rule set before launch: ship, revert or extend. The founder approves anything live.
Update — The baseline is recomputed on the new version, the threshold is re-fitted if needed, and the alert is labeled real or false.
the objects
A threshold, and the firing it produces.
Thresholds are data, not code. Each one is a versioned row, so changing a level is a logged decision with a reason, and old firings stay readable against the version that fired them.
| Field | Type | What it holds |
|---|---|---|
threshold_id | text | Stable id, e.g. thr.det.precision |
version | int | Bumped on every change to level, window or action; firings point at the version |
metric_id | text | Points at one metric definition (Funnel and metrics), never a formula inline |
stage | int 1–12 | Which pipeline stage it watches |
scope | enum + id | account · product · campaign · detector · play · source; null id means every one |
type | enum | floor · ceiling · control limit · change vs baseline · sample-size gate · staleness · event |
window | duration | Rolling window or last-N units the metric is read over |
min_sample | int | Below this, the threshold stays silent |
level | number + unit | The line itself, or the sigma width for a control limit |
severity | enum | info · warn · critical |
action | enum | What a firing does (see action types) |
owner | enum | system · founder · agent: who acts or approves |
cooldown | duration | Minimum gap between firings of the same threshold and scope |
created_from | learning_id | The readout or learning that set this level; null for a starting rule of thumb |
false_alarms | int | Firings labeled not real, used to re-fit |
status | enum | active · muted (with reason and until) · retired |
a detector precision threshold
{
"threshold_id": "thr.det.precision",
"version": 3,
"metric_id": "detector_precision_rolling",
"stage": 5,
"scope": {
"kind": "detector",
"id": null
},
"type": "floor",
"window": "last 50 founder labels",
"min_sample": 50,
"level": {
"value": 0.6,
"unit": "share"
},
"severity": "warn",
"action": "auto_shadow",
"owner": "system",
"cooldown": "7d",
"created_from": null,
"false_alarms": 0,
"status": "active"
}| Field | Type | What it holds |
|---|---|---|
alert_id | uuid | One row per firing |
threshold_id + version | ref | Exactly which line fired |
scope_id | text | Which detector, play, campaign or source |
value | number | The metric at firing time, frozen |
sample | int | How many units it was computed on |
baseline | object | The baseline and limits it was compared against, frozen |
fired_at | timestamp | When it crossed |
action_taken | enum + ref | What ran, with the id of what it created (hypothesis, replay, pause) |
acked_by | enum | system · founder · agent, and when |
label | enum | real · false alarm · unsure: set by the founder or by the readout |
outcome | object | Did the action help: metric at +7 and +28 days, and the readout id if a test ran |
one firing of it
{
"alert_id": "al_7f3c…",
"threshold_id": "thr.det.precision",
"version": 3,
"scope_id": "det.public_pain.reddit",
"value": 0.52,
"sample": 50,
"baseline": {
"value": 0.71,
"weeks": 4
},
"fired_at": "2026-10-20T13:05:00Z",
"action_taken": {
"kind": "auto_shadow",
"hypothesis_id": "hyp_det_vocab_v4"
},
"acked_by": "system",
"label": null,
"outcome": null
}action types
What a firing is allowed to do.
Ordered from least to most reach. The system can take the first four on its own because they stop or narrow something and are easy to undo. Anything that changes what a real person sees needs the founder.
system — Log only · Writes the alert. Feeds forecasts and false-alarm counts. Nobody is interrupted.
system — Alert · Notifies the owner with the value, the baseline and a link to the slice.
system — Auto-shadow · Moves a detector or lane to shadow: it keeps running and logging, but stops filling the list.
system — Auto-pause · Stops a campaign, step or source immediately. Used for reputation and data-integrity guardrails.
agent — Queue offline replay · Re-runs the next version of a prompt, rule or scorer on stored items and labels. No live risk.
agent — Open hypothesis · Writes one hypothesis into the registry with the alert as evidence. Nothing changes yet.
agent → founder — Propose test · Drafts a full test: arms, unit, metric, sample size, win rule. The founder approves before it runs.
agent → founder — Propose retire · Suggests switching off a detector, play or fit line that keeps underperforming.
agent — Re-fit threshold · Recomputes a threshold's level from recent history after too many false alarms, as a new version.
cadences
Three speeds of checking.
live · minutes — Guardrails · Stop requests, touched holdouts, step errors, missed sends, Hot leads aging. Fire within one dispatcher tick; actions are pause, shadow or alert.
daily · each morning — Snapshot checks · Every rate threshold and control limit reads the daily snapshot. Firings queue replays and open hypotheses for the agent to work through.
weekly · Monday — The review · Rung control charts, the pace line to the goal, false-alarm counts. The founder picks one constraint and approves at most one live test.
tuning the thresholds themselves
A threshold is a hypothesis too.
Every starting level on this page is a rule of thumb, not a measured fact. The loop treats its own lines like any other knob: each one starts from a baseline, gets scored on its firings, and gets re-fitted on a schedule.
Start from a baseline — Before a threshold goes live, compute its metric over the last 4 to 8 weeks. Start the level at the rule of thumb or at the baseline's control limit, whichever is wider.
Run it silent first — New thresholds fire as log only for 2 weeks. Count how often they would have fired.
Label every firing — Each firing gets real, false alarm or unsure. The readout of any test it opened settles the label.
Re-fit monthly — Recompute the baseline and limits on the current version of whatever it watches. More than half false alarms widens the line; a labeled miss tightens it.
Version every change — A new level is a new version with a reason and a created_from learning id. Old firings stay tied to the version that fired.
Retire dead lines — A threshold that hasn't fired in 90 days and watches nothing critical becomes log only. Fewer, sharper lines beat a wall of alerts.
the two errors
A false alarm fires when nothing was wrong; it costs attention and trains people to ignore alerts. A miss stays quiet while something was wrong; it costs leads and reputation. Guardrails on reputation (stop requests, touched holdouts) accept more false alarms. Diagnostic lines (rung conversion, edit drift) accept more misses. The math is on Control limits and alert math.
starter thresholds
Twenty lines to start with, across all twelve stages.
Levels are starting rules of thumb, not sourced numbers. Expect to re-fit most of them after the first month of firings. The full catalog, with every field, is on Threshold catalog.
| Stage · metric | Type | Level (rule of thumb) | Min sample | Severity | Action | Why |
|---|---|---|---|---|---|---|
| stage 1 · Link Intake completion rate (links in → finished briefs) | Change vs baseline | Down 30% against its 4-week baseline window: 7 days | 30 intake starts | warn | Open hypothesis founder | A copy or step change broke the intake. Opens an intake copy or step-order test. |
| stage 2 · Brief Founder correction rate, per brief field | Ceiling | Over 25% of one field's values corrected window: 30 days | 20 briefs | warn | Queue offline replay agent | The extractor is wrong on that field. Replay the next prompt version on every corrected case before shipping it. |
| stage 3 · ICP Share of reviewed leads the founder marks never | Ceiling | Over 40% window: 7 days | 30 reviews | warn | Open hypothesis agent | The filter lets in people the founder won't contact. Test tighter not-if lines by replaying past reviews. |
| stage 4 · Trigger Reply rate on signals older than the trigger's freshness window | Floor | Under half the reply rate of fresh signals window: 60 days | 40 touches in each age bucket | info | Propose test agent | The window is too long. Propose a shorter fresh_for, judged on the next 60 days. |
| stage 5 · Detector Detector precision (founder labels real ÷ labeled) | Floor | Under 60% over the last 50 founder labels window: rolling 50 labels | 50 labels | warn | Auto-shadow system | Move the detector to shadow so it stops filling the list, and open a rule test. |
| stage 5 · Detector Matches per day, per detector | Control limit | Above the upper control limit (about 3× the 4-week daily median as a first cut) window: daily | 14 days of history | warn | Alert only system | Spam waves and viral threads look like demand. Alert; shadow it if precision drops too. |
| stage 5 · Detector Source freshness (newest item age) | Staleness | Past the source's own max staleness window: continuous | n/a | warn | Alert only system | Mark the source's health stalled and alert. |
| stage 5 · Detector Share of runs ending partial or error, per source | Ceiling | Over 10% of runs in 24 hours window: 24 hours | 10 runs | warn | Alert only system | |
| stage 6 · Signal Judge and founder disagreement on labeled signals | Ceiling | Over 20% window: 14 days | 40 labels | warn | Queue offline replay agent | Replay the next judge prompt on every labeled case; ship only if agreement goes up and recall doesn't drop. |
| stage 6 · Signal Oldest untouched item in the pain queue | Staleness | Over 72 hours window: continuous | n/a | warn | Alert only founder | Signals decay. Tell the founder before the window closes. |
| stage 7 · Lead Reply rate of the daily top 10 | Control limit | Below the lower control limit for 2 weeks running window: weekly | 30 touches a week | warn | Propose test agent | The ranking stopped finding responders. Propose a scorer change, replayed on frozen features first. |
| stage 7 · Lead Hot lead with no touch | Staleness | Over 48 hours window: continuous | n/a | warn | Alert only founder | A hot lead going cold is the most expensive miss in the pipeline. |
| stage 8 · Playbook Reply rate per touch, per play | Control limit | Below the play's lower control limit window: rolling 4 weeks | 30 touches | warn | Propose test agent | Open an opener test on that play. Don't change the play and the opener at once. |
| stage 9 · Campaign Stop requests per 100 touches | Ceiling | Over 2 per 100 window: 7 days | 50 touches | critical | Auto-pause system | Pause the campaign now. Reputation damage compounds faster than any test can measure. |
| stage 9 · Campaign Holdout leads who received a touch | Ceiling | Any window: continuous | n/a | critical | Auto-pause system | A touched holdout voids the lift readout. Pause and alert. |
| stage 10 · Sequence Median draft edit distance | Change vs baseline | Up by a third week over week window: weekly | 20 decided drafts | warn | Queue offline replay agent | The drafter drifted from the founder's voice. Replay the current prompt against recent edits to find where. |
| stage 11 · Funnel | Floor | Behind the line window: weekly | n/a | warn | Monday review founder | The Monday review picks the weakest rung as the constraint and opens one hypothesis on it. |
| stage 11 · Funnel Conversion of one funnel rung | Control limit | Below its lower control limit 2 weeks running window: weekly | 30 entering the rung | warn | Open hypothesis agent | That rung is the constraint. Open one hypothesis on it, not three. |
| stage 12 · Loop Experiment past its judge-by date with no readout | Staleness | Over 48 hours window: continuous | n/a | warn | Alert only founder | Every test gets read, win or lose. |
| stage 12 · Loop Share of a threshold's firings labeled not real | Ceiling | Over 50% of its last 10 firings window: last 10 firings | 10 firings | info | Re-fit threshold agent | The threshold cries wolf. Re-fit its level from the last 8 weeks and version the change. |
illustrative example
One week of the loop, before launch.
Here is how the loop would handle that week. Every figure below is an illustration of the mechanics, not a measurement.
Monday: the pace line fires — thr.fun.pace: joins are behind the straight line to the goal. Severity warn, action Monday review. The founder opens the review with the rung chart beside it.
The weakest rung is brief offered, not found. One hypothesis: offer the brief in the first reply to Hot leads.
Tuesday: a detector floods — Illustration: a Reddit pain detector's matches jump past its upper control limit after a viral thread. The spike threshold alerts. Precision over the last 50 labels falls under 60%, so the precision threshold auto-shadows it and queues a vocabulary replay.
Wednesday: the replay reads out — The new vocabulary is replayed on stored matches with founder labels. Precision recovers without losing labeled-real matches, so the agent proposes the switch. The founder approves; the detector goes live on the new version.
Thursday: edit drift
Illustration: the median edit distance on reply drafts rises by a third week over week. The agent replays the current prompt on the week's edited drafts and finds the opener is what gets rewritten. It proposes an opener test, which joins the queue behind the brief-offer test, since one live test per knob.
Sunday: label the week — Each firing is labeled. The flood was real; the edit drift turned out to be one long thread. One false alarm goes against that threshold, and nothing is re-fitted yet.
data to capture
Firings are labels.
record — Every threshold version, every firing with its frozen value, sample and baseline, every action and the ids it created.
label — Each firing: real, false alarm or unsure. Each action: did the metric recover by +7 and +28 days.
trains — Better thresholds (re-fitted levels per scope), an alert-priority model (which firings turn out real), and the improvement agent's proposal ranking.
test — Threshold changes are themselves tested: run the new level silent beside the old one for 2 weeks and compare firings against labels.