Part 5 of 7 · Churn predictor series ~5 min read

How a win-back gets tracked

The weekly list lands in Dan’s Slack DM at 8:03am Monday. Greenfield Cafe is near the top: no order in 34 days, one sour ticket. There are three buttons next to the name. What happens when he taps one? The honest answer is “it depends on what actually happened with the customer.” This post walks through the three things the predictor can record on a name — reached out, won back, lost — and how the state, the score, and the audit trail all stay in sync.

Key takeaways

  • Three actions per name: reached out (log and pause), won back (save and reset to steady), lost (record the churn).
  • Each action updates the cp-state table and writes an audit row.
  • A win-back resets the customer’s score so the next slip starts a fresh cycle.
  • A loss records a reason so the monthly summary can show why customers leave.
  • The buttons are a Slack interactive message backed by a Function URL.

Three actions on a name

Three actions on each name in the list A diagram showing one input on the left flowing through a small interactive Slack panel, then branching into three action paths. Far left: a "Name in the weekly list" box showing a typical entry — customer name, days since last order, monthly value, the plain reason — with three Slack-button placeholders below: Reached out, Won back, Lost. The owner taps one button. The middle column shows the three branches. Branch one, Reached out: records that the owner has made contact; a Function URL Lambda writes the contact date to the cp-state table, which pauses re-flagging of this customer for the pause window (default two weeks), and writes a contacted event to the audit trail. The score isn't changed — the customer is still at-risk, just being worked. Branch two, Won back: marks the save; the Function URL Lambda resets the customer's score in cp-state to steady, records the save amount as the recovered monthly value, and writes a won-back event to the audit trail. The customer drops off the list and the next slip will start a fresh cycle. Branch three, Lost: records the churn; an optional one-tap reason field captures why (price, competitor, went quiet, other); the Function URL Lambda marks the customer as lost in cp-state and writes a lost event with the reason to the audit trail. The right side shows the convergence: every action writes a row to the cp-audit DynamoDB table with timestamp, customer id, action, by-user, and notes. A note at the bottom: marking a name doesn't message the customer — it records what the human did, so saves and losses are countable later. Name in the list name, days, value, reason [Reached out] [Won back] [Lost] Action 1 Reached out • Logs the contact date in cp-state • Pauses re-flagging • Score unchanged Action 2 Won back • Resets score to steady in cp-state • Records recovered monthly value Action 3 Lost • Marks customer lost with a reason • No message sent — just recorded Audit trail DynamoDB cp-audit timestamp · customer_id action · by-user notes Marking a name doesn’t message the customer — it records what the human did, so saves are countable.
Fig 5. Three actions per name, three different effects. Reached out logs the contact and pauses re-flagging. Won back resets the score and records the save. Lost records the churn with a reason. Every action writes to the audit trail.

Action 1: reached out (the most common)

Dan calls Greenfield, has a good conversation, and now wants the predictor to know he’s on it. He taps Reached out. No modal needed — it’s one tap. The button submits to a Function URL Lambda. Two things happen. First, the Lambda writes today’s date to the customer’s last_contact field in cp-state, which the hand-off’s Gate 3 reads next week to keep Greenfield off the list during the pause window. Second, a reached_out row is written to cp-audit with the user and timestamp.

The score itself isn’t changed — Greenfield is still genuinely at-risk until the signals improve. Reached out just means “a human is handling this; don’t nag.” If the customer starts ordering again, the order feed will lift their signals naturally and the score falls on its own. If they don’t, Greenfield reappears on the list when the pause ends, which is exactly the prompt Dan needs to follow up.

Action 2: won back (the save)

A week later Greenfield places a big order. Dan taps Won back. The Function URL Lambda resets the customer’s score in cp-state to steady, clears the surfaced and contact fields so the cycle starts fresh, and records the recovered monthly value (defaulting to the customer’s value from the list, editable if the relationship changed). A won_back row goes to cp-audit with the user, the timestamp, and the saved value.

Recording the save matters for more than tidiness. It’s how the business finds out the predictor is worth running. The monthly summary in Part 6 adds up the recovered value across all the saves — “the team won back $3,400 of monthly revenue this month from eleven at-risk customers” — which is the number that justifies the two dollars of AWS spend many times over. A win-back the team made but never recorded is a save the business can’t see.

Action 3: lost (the honest record)

Sometimes the customer is gone. They found a cheaper supplier, or their needs changed, or they went quiet and never came back. Dan taps Lost. An optional one-tap reason field offers a few choices — price, competitor, went quiet, other — so the loss isn’t a mystery later. The Function URL Lambda marks the customer as lost in cp-state (so the scorer stops surfacing them) and writes a lost row to cp-audit with the reason.

The reasons add up into something useful. If half the month’s losses are tagged “price,” that’s a pricing conversation, not eleven separate failures. If most are “went quiet,” the predictor probably needs to flag earlier — a hint to tighten the weights in the rules doc. The lost record turns each departure from a number on the revenue chart into a small, honest note about why, and nothing about marking a customer lost ever reaches the customer — it’s purely an internal record.

Every action is logged, every count is honest

The cp-audit table records every reached-out, won-back, and lost with the user who took the action, the timestamp, and a snapshot of the customer’s score and band at the time. If a button gets tapped by mistake — Lost instead of Reached out on a fat-fingered Monday — a rep can run an “undo last action” through a small admin command that reads the snapshot and restores the state. The undo is itself an audit row, so the trail stays clean.

This trail is what makes the monthly summary trustworthy. When it says the team saved eleven customers and lost four, those aren’t estimates — they’re counted button taps, each tied to a person and a moment. The predictor’s whole value rests on the team trusting the list, and the team trusts the list because the outcomes are recorded honestly and nothing happened behind their back.

Next post: the cost breakdown. The whole pipeline above runs in coffee-money territory at SMB volume; Part 6 explains exactly where the dollars go and why the weekly run keeps it so cheap.

All posts