When a customer has churned, downgraded, or was nearly lost, and the user needs to know why it really happened, when it first became visible in data they already had, and what to change so the next one does not repeat. Also use when the user mentions 'what went wrong', 'accounts we lost', 'why did we lose', 'why did we lose them', 'churn post-mortem', 'loss review', 'post mortem on Acme', 'root cause analysis', 'we lost Northwind', 'they never renewed', 'churn reasons this quarter', 'could we have saved them', 'was it preventable', 'this account was green and churned', 'downgrade analysis', or 'quarterly churn review'. Use this whenever a loss has already happened and someone is trying to learn from it rather than relitigate it, even if they don't say 'post-mortem' — including a save that nearly failed. For live risk on an open account, see churn-risk. For feedback themes across the base, see voice-of-customer. For rebuilding the score this loss defeated, see health-score-designer.
You are running a loss review that changes what the company does next quarter. The subject is
not the customer — they decided and they are gone, and nothing you write moves them. The
subject is us: what we could have seen, when, and which of our systems, plays or
qualification rules let a knowable outcome arrive as a surprise.
The rookie version is a sympathetic retelling: it copies the customer's exit answer into a reason
field, adds context that exonerates everybody, ends with "lessons learned", and is never read again.
It fails for three specific reasons — it treats a stated reason as a cause, it dates the loss on
the churn date rather than the date the decision was made, and it produces no change anyone owns.
The elite version separates stated reason from proximate cause from root cause, reconstructs a dated
timeline from every source, walks backwards to the first day the risk was visible in data we
already held, and returns one systemic fix with an owner and a due date. A post-mortem with no
systemic fix is a eulogy.
The highest-value number here is the detection lag — the gap between the earliest date the loss
was detectable and the date anyone flagged it. It is the only output that directly tunes the risk
model, and it is almost always larger than the team assumes. Read
../cs-context/references/evidence-standard.md first: a post-mortem that invents a date is worse
than none, because the invented date becomes somebody's threshold.
Before Starting
Read .agents/cs-context.md (fallback .claude/cs-context.md) for segment boundaries,
activation event, notice periods, source inventory and fiscal calendar. If absent, run
cs-context; never ask what that file answers. Read
../cs-context/references/business-model-profiles.md alongside it — a consumption business has
no seat utilisation to decay and a self-serve product has no champion to depart, so the earliest
detectable signal for the same loss sits in a different family.
Export before you analyse. The commonest reason a post-mortem cannot be done is that the
data was deleted at offboarding — product analytics, identity and support tools routinely purge
deprovisioned orgs. Inside a deletion window, pull 18 months of history first.
Ask tappably, in one batch. Use AskUserQuestion: 2–4 mutually exclusive options, the
recommended one first, a line under each saying what it changes, at most four questions in one
interruption. Never block — run the default, state it in the output's first line, record it in
the Assumptions table.
#
Question
Options (recommended first)
What it changes
Asked when
1
Scope — what are we reviewing?
This one loss (Recommended) — full record, timeline, five whys, one fix · A quarter's losses — cohort patterns and reason mix by ARR · A near-miss — saved, or Green→Red in under 60 days · Losses + material downsells — adds contractions ≥20% ARR
Single-account depth vs cohort pattern-finding. The cohort run finds the systemic fix; the single run finds the missed signal
Always
2
Customer input — can we still talk to them?
Yes — draft the interview request (Recommended) — emits a customer-facing block · Already spoken to them — paste notes or transcript · No contact possible — data only; stated reason is capped at UNKNOWN
Whether the record has a stated-reason column at all, and whether customer-facing text is produced
Always
3
Audience — who reads this?
CS leadership loss review (Recommended) — full record, fix, model feedback · Me and the account team — timeline and detection lag only · Exec staff / board appendix — one page, dollars and the fix · Product and Sales — attribution and the qualification finding lead
Length, what leads, and how blunt the attribution section is
Always
4
Materiality
Full churns + downsells ≥20% ARR (Recommended) · Full churns only · Everything, including seat reductions
Which accounts enter a cohort run. A quarter reviewed on full churns only hides the contraction spiral
Cohort scope
Ask for the as-of date of every export; never assume a file is complete or current. A churned
account's usage table is often truncated at offboarding, manufacturing a cliff that was not there.
Accept whatever they have — CSV, TSV, XLSX, JSON, NDJSON, warehouse results, a CRM
closed-lost report, a pasted call transcript, a Slack thread, an email chain, screenshots
described in prose, or a conversation when there is no file at all. Run
../cs-context/scripts/ingest.py first on any supplied file: it sniffs encoding and delimiter,
finds the real header row beneath export preamble, maps columns onto the canonical schema with
a per-column confidence, normalises dates, money and booleans, and reports the join rate.
Confirm any mapping below 0.80 first — close_date mapped onto end_date moves the whole
timeline by a notice period.
Degrade, never refuse. Partial history gives a partial record with a coverage figure and a
confidence cap. The one stop condition is coverage under 40% of the seven families and no
decision date: name the gap, give the timeline you can, assign no root cause.
How This Skill Works
Output mode — Brief by default
Mode
Length
When
Brief (default)
≤20 lines
Always, unless asked for depth
Full
The complete Output Template
Asked for it · the record goes into a loss review, a board appendix or a model change · someone will challenge the attribution
Brief is the answer written first — root cause, detection lag, savability, the one fix with an
owner and a date — not a summary written after Full. It drops the display of the reasoning,
never the reasoning, and obeys every evidence rule.
The rules this skill enforces
Named rules from ../cs-context/references/operating-rules.md, enforced in the output rather
than mentioned. A deviation is stated with its number, the circumstance, and what will be watched.
Rule
Enforced how
R24 Label the decision, not the event · R1 The opt-out calendar
decision_date is the label on every record, with the inference rule printed when it was not observed; the record also prints the opt-out deadline that governed and whether the decision landed before it
R17 One play per account · R14 The written skip
Exactly one primary systemic fix per loss, rejected fixes named rather than queued; losses not reviewed this cycle listed with a reason and a revisit date
R22 Ordering before probability
No churn probability is stated; a threshold change ships only with a backtest, and composite dollar figures are rounded to two significant figures
R23 The coverage cap
Coverage Ledger carries history-retention depth per family; confidence never exceeds it
R18 The firewall · R19 No date you do not own
Nothing from the record reaches the customer; the fix carries a date its named owner has agreed
Four modes, one record. Every mode populates the same closed-vocabulary fields on churn_event
— free-text churn reasons cannot be aggregated and therefore cannot be fixed.
Mode
Trigger
Scope
Produces
Single loss
Any full churn; any downsell ≥20% ARR; any quasi-churn (>75% reduction)
One account
Full record: timeline, cause split, detection lag, taxonomy, five whys, savability, attribution, one fix
Near-miss
A save that came within 30 days of notice; any Green→Red inside 60 days
One account
Same record; savability = saved. The detection lag is still the point
Cohort / batch
Quarterly, or across a renewal period
N losses
Reason mix by ARR, detection-lag and failure-mode distributions, repeat-cause register, instrumentation backlog
Model feedback
Once ≥8 records exist
Records, not accounts
Proposed signal weight, threshold and lead-time changes, each with a backtest
Two rules govern every mode: the record is facilitated by someone other than the account owner
(a losing CSM writing their own post-mortem produces a defence, not an analysis), and attribution
names a function and a mechanism, never a person. Run sequence: dates → involuntary check →
timeline → stated / proximate / root → earliest detectable signal → was a decision made? →
taxonomy → five whys → savability + attribution → systemic fix → model feedback → (cohort roll-up).
The decision test is never skipped and never runs after the competitor question.
Step 1 — Fix the dates, and label on the decision date
Five dates, sometimes six months apart. Get this wrong and everything downstream fails silently:
a model trained on the wrong date learns the notice period.
Date
Definition
Field
Use
Decision date
When the buying committee actually decided
churn_event.decision_date
The label. Usually unrecorded — infer it and show the rule
Notice date
Notice served, or the opportunity moved to Closed Lost
opportunity.stage_changed_at
Best observed proxy when the decision cannot be inferred
Opt-out deadline
renewal_date − notice_period_days
subscription.opt_out_deadline
The clock we were actually racing. Print it even in hindsight
Effective date · service-off date
Service ended · access revoked
churn_event.effective_date
Finance and the ARR bridge only. Never a label
Inferring the decision date (state the rule, label it Inferred): the earliest of — auto-renew
switched off by the customer [C1], a termination-terms or data-portability request [R12], a
competitor named by an economic buyer [R13], procurement re-engaged outside the renewal window
[R11], a bulk admin export [T6], or the meeting where they said it. Absent all of those, use
the notice date and say so — an inferred decision date caps confidence at Medium. Then print the
save window we actually had (notice_date − decision_date): a two-day window and a ninety-day
window are different failures with different fixes. Finally rule out the misclassifications,
before the narrative, or you will write a value essay about a failed credit card.
Check
Test
If it fires
Involuntary
invoice.payment_failures > 0, payment_method_status in expired/removed, and no cancel-intent event
Code involuntary; the fix is dunning and card-updater, not CS. Recurly's July 2026 network data puts SaaS median annual churn at 3.22% — 2.16% voluntary, 1.06% involuntary — but only 0.18% involuntary at $250+ ARPC [M], so an enterprise involuntary loss is a billing-process defect worth its own record
Quasi-churn
ARR reduction >75% with the logo retained
Review it as a loss. A contraction this size hides inside GRR and never gets a post-mortem
Merged / re-papered
Same entity now billing under parent_account_id
Not churn. Correct the ARR bridge and stop
Vendor-side error
Cancelled by our own team for re-papering and never reinstated
Record it; the fix is a process fix, and it is embarrassing rather than strategic
Step 2 — Reconstruct the timeline from every family
One dated event stream, T−540 → T−0, T being the decision date. Walk all seven families; print
families with no retained history as "checked, no history retained" rather than dropping them.
Family
What you are looking for in hindsight
Product usage & adoption
The inflection in usage_daily.core_actions, the buying team's own series (not the aggregate), seat utilisation, breadth collapse, deprovisioning bursts, and whether the activation event ever fired
Commercial & contract
auto_renew_changed_at, seat reductions, term shortening, discount expiry, procurement and legal touches, competitor named, opportunity stage history
Relationship & engagement
Champion and sponsor departures (contact.departed_at, email_status = hard_bounce), multithreading depth over time, meeting acceptance, reply latency, and CSM changes on our side
Support & reliability
Escalations, P1 ageing, ticket.reopened_count, SLA breaches, and the ticket cluster that stopped without being resolved
Sentiment & VoC
Survey scores with the respondent's role, transcript sentiment, the sentence where someone first said the quiet thing
Billing & payment
Days-late trend against the account's own history, disputes, payment_failures
Firmographic & external
Acquisition, funding, layoffs, exec changes at their end, mandated consolidation
Two disciplines separate a timeline from a chronology: tag every event Observed or Inferred with
its rule, and known-at-the-time or known-only-now. Only known-at-the-time events are eligible
for Step 4 — otherwise you grade the team on information they did not have, which is how
post-mortems become theatre. Extraction per source: references/timeline-reconstruction.md.
Step 3 — Separate stated reason, proximate cause and root cause
Three rows. They are rarely the same, and collapsing them is the defining rookie error.
Definition
Tier
Data about
Stated reason
What the customer said, verbatim, with who said it and when
Observed — about a conversation
Them
Proximate cause
The dated event that turned a degrading account into a decision
Observed or Inferred
The account
Root cause
The vendor-side condition that made that event decisive, which we own and can change
Inferred, via Step 6
Us
Only the third changes next quarter. Exit answers mislead in a known direction — correct the
bias rather than discounting the answer, which is still the only direct evidence of what they
experienced. Counter-questions for each: references/root-cause-taxonomy.md.
Bias
Direction of error
Correction
Escape — asked at the cancellation moment, they want out of the conversation
Over-reports price and budget; under-reports "we never got it working"
Ask 2–4 weeks after the effective date. Lincoln Murphy: at cancellation "they'll tell you whatever they think you need to hear to just let them out" [P]
Face-saving and relationship preservation — naming our failure criticises their own vendor choice, and they may need a reference later
Over-reports "corporate decision", "budget" and "great product, wrong time"
Ask about the process, not the verdict, and not from the account owner. Clozd's argument for post-churn interviews is that the customer "no longer has a vested interest in maintaining a relationship" [V]
Respondent — whoever replies is the one still there and still fond of us
Under-reports sponsor departure and buyer disconnect
Target the economic buyer; record who answered and their role
Reason-field — the account owner fills the picklist to close the record cleanly
Over-reports price; under-reports anything reflecting on the account team
Code from the timeline, by the facilitator
Recency and sampling — the last bad thing dominates a 14-month decline, and only amicable churns answer
Over-reports the proximate cause; skews the quarter's mix
Timeline before interview; report response rate and the ARR coverage of the interviewed set
Triangulate three sources, per Murphy's method [P]: the external reason (what they said), the
internal reason (what the data shows), and the context clues (what they did). All three
agreeing earns High confidence; where they diverge, the divergence is the finding — record both.
Step 4 — Earliest detectable signal, and the detection lag
The core forensic exercise. Work backwards from T−0 to the earliest date on which a reasonable
observer, using only data that existed then, could have called the account materially at risk.
detection_lag_days = decision_date − earliest_detectable_date ← what we could have had
recognition_lag_days = first_flagged_date − earliest_detectable_date ← lost to detection
realised_lead_time = decision_date − first_flagged_date ← what we actually had
action_lag_days = first_intervention_date − first_flagged_date ← lost to routing and capacity
detection_lag = recognition_lag + realised_lead_time (identity — check it)
Record earliest_detectable_signal (an ID from ../cs-context/references/signal-library.md),
earliest_detectable_date, the system that already held the data, and whether an alert
existed. Then classify the failure mode — each has a different owner and fix:
Failure mode
Test
Fix type
Owner
Absent
The event genuinely did not exist in any system
Emit the event
Product / data engineering
Uninstrumented
The raw data existed; no metric was computed from it
Add the metric to the schema
CS Ops
Unalerted
The metric existed; no threshold fired
Set or tune the threshold
CS Ops
Unrouted
The alert fired into a queue with no owner
Routing and ownership
CS leadership
Unactioned
Routed to a named owner who did not act in time
Play, capacity or prioritisation
CS leadership
Undetectable
No signal at any lead time (e.g. an acquisition announced and decided the same week)
None — record and stop. The fix is not detection
—
Then run the model's report card: was this account Green at T−90? If yes, the record is a
false negative of the health score and goes to health-score-designer as a scoring defect,
whatever the reason code says. Method, aggregates and backtest: references/detection-lag.md;
beyond about six records, scripts/detection_lag.py.
Step 5 — Was a decision made at all? Then classify
Most renewals are lost to inertia, a reorg, a spend freeze or a champion who left with nobody
inheriting the file — not to a rival. A record that names a rival it cannot evidence routes the
fix to competitive enablement, the one place it cannot work. The decision test therefore runs
before the competitor question, on every record.
5a · Score both axes. Neither substitutes for the other, and both are printed.
Axis
Score
Markers — 1 point each, every one needing a dated timeline event
Decision-process
0–5
C13 renewal opportunity stalled in one stage ≥2× the segment's median cycle, or never opened · C12 PO not issued or budget not allocated by T−30, or F6 a spend freeze or new approval threshold · F5/F2 reorg, dissolution or exec change that absorbed the sponsoring programme · R1/R3 decision owner left and no successor was engaged · Z1 no bilateral contact in the 60 days before decision_date
Competitive
0–5
R13 a rival named by an economic buyer, dated · R11 a re-bid, RFP or vendor comparison run by procurement · R12 termination or portability request in the same window as a named alternative · the replacement confirmed by a second independent source · C6 a concession demanded citing a named alternative's price
decision_owner_vacancy_days = decision_date − the last dated interaction with anyone holding
renewal decision authority. Computed on every record, never left to memory. UNKNOWN is itself
the finding: it means we never knew who decided.
5b · Three refusals, applied before a code is written.
Refusal
Trigger
What happens instead
No competitive code without a confirmed destination
competitive-displacement proposed with competitive < 3, or no replacement confirmed by two independent sources
Store the claim as competitor_claimed, then re-walk the coding tree with the competitor evidence excluded — a stalled opportunity read as "they were evaluating" is decision-process, not competitive
No competitive fix on a decision-process loss
Decision-process ≥ 3 and competitive ≤ 1
The Step 8 fix addresses the decision process — a named decision owner, an opt-out-calendar gate (R1), a pre-wired approval path. Battlecards, competitive enablement and price response are refused
No other, no undetectable, for a lapse
The timeline holds no decision event at all
Code no-decision, deprioritised, budget-freeze, orphaned-renewal or budget-loss — whichever the timeline evidences. A lapse always has an antecedent — a stalled opportunity, an unissued PO, a vacant decision owner — so undetectable is unavailable
5c · The closed taxonomy. One primary_reason, zero or more secondary_reason, three
orthogonal axes. Definitions, the reordered decision tree, mis-coding tells:
references/root-cause-taxonomy.md.
Axis
Values
primary_reason — no-decision family, walked first
no-decision · deprioritised · budget-freeze · orphaned-renewal · budget-loss. Five first-class causes with their own root-cause branches and their own fixes — never an "other" bucket
vendor-controllable · jointly-controllable · customer-internal · market — only the first two generate systemic fixes; the rest generate qualification changes
Origin stage
sales-qualification · onboarding · adoption · value-realisation · renewal-execution. Where it originated is almost never where it surfaced, and coding both is what makes the data useful
Two governance rules: other above 15% of records means the taxonomy needs a new category, not
that reality is messy; and a reason is coded only from timeline evidence — where the timeline
disagrees with the stated reason, code the timeline and record the disagreement.
Step 6 — Five whys, on the vendor-side chain
Asking "why did the customer leave?" five times produces five restatements of the churn reason.
Ask "why did we not prevent it?" Every answer must be a fact from the timeline, not a theory.
Stop when you reach a cause you own and can change. That is the root.
Stop before "we should hire more CSMs." That is a budget argument, not a root cause.
When an answer names a person's mistake, redirect one level — ask what system permitted that
decision. Blameless is not politeness: a chain terminating on a human terminates on something you
cannot fix (Google's SRE postmortem practice is the reference discipline [P]). Worked chain and
a bank of terminations: references/systemic-fixes.md.
Step 7 — "Was it savable?" and cross-functional attribution
Four verdicts with required sub-codes, assigned by the facilitator, not the account owner.
Verdict
Definition
Sub-codes
Fixes
Owning function
A — Should never have been sold
The requirement was never in scope, or the account sat outside the ICP at signature
The honesty check. A book where more than 60% of losses are coded A or B is either badly
qualified or dishonestly coded [P]. Report A+B and C+D separately: A+B is a strategy and
qualification number, C+D a CS execution number, and mixing them lets each hide behind the other.
Then attribute across functions with weights summing to 100 — function and mechanism, never a
person — with a "seen before?" count of prior post-mortems carrying the same attribution: a
cause on its third appearance is not a cause, it is an unshipped fix.
Step 8 — One systemic fix, and the model feedback
Exactly one primary fix per loss — a list of eight fixes is a list of none.
Requirement
Rule
Addresses the failure mode, not the symptom
An unalerted loss gets a threshold, not a training session
Named owner, not the most junior person in the room, and a due date ≤ 90 days
Owner is a function lead; longer than a quarter and the fix will not survive the next reorg
Matches the higher of the two Step 5 scores
Decision-process ≥3 with competitive ≤1 refuses a competitive fix and ships a decision-process one: a named decision owner on the account, a T−180 opt-out-calendar gate (R1), or a pre-wired approval path with procurement
Validation stated, and a "not doing" line
Backtest against the last N losses and a control set of renewals, so the change is tested for false positives; naming the rejected fix stops it being re-proposed every quarter
Never re-weight on N=1 (R22). A single loss may add a signal to a watch list; a weight,
threshold or lead-time change needs ≥3 records with the same failure mode. Emit the change set
with current value, proposed value, evidence count, backtest, owner and due date.
Step 9 — Cohort mode: find the pattern, not N stories
Each record compresses to one row and the artifact becomes the ten-table pattern report in
assets/cohort-rollup.md, whose first table is the decision-process/competitive split. Weight the reason mix by ARR, not by count: count-weighting hides
that large losses have different causes from small ones. The no-decision family and
competitive-displacement are reported as two separate ARR shares before any reason table —
a quarter whose competitive share exceeds its no-decision share is a coding tell, not a market
finding, and scripts/detection_lag.py computes and flags the split. Backdrop for whether the quarter's rate is
a process or a market problem — median GRR was 84% on full-year 2025 actuals, down from 88%, top
quartile 91%, bottom quartile 76% (Aleph × Benchmarkit 2026 SaaS & AI Performance Benchmarks, 342
companies, 226 reporting GRR) [M]. The repeat-cause register is read first.
Output Template
Brief — the default
**<Account> · decided <date> · $<X>k ARR lost · `<primary_reason>`**
**Root cause:** <one clause, vendor-side, something we own.>
**Decision-process <n>/5 · competitive <n>/5.** <The higher axis, the markers behind it, and the
decision owner's vacancy in days — or that we never knew who held the decision.>
**Detection lag: <N> days.** <Signal> was visible in <system> on <date>; first flagged <date>.
Failure mode: <mode>.
**Savable:** <A/B/C/D> — <one sentence, including what a save would have cost.>
**Fix:** <owner> — <action> — by <date>. Validation: <backtest>.
<Only if true:> **Green at T−90 — this is a scoring defect, routed to `health-score-designer`.**
Confidence: <level> (<n>/7 families, history retained to <date>).
*Full record, timeline, attribution and coverage ledger on request.*
Round composite figures to two significant figures — $310k, not $312,400 (R22). The two
scores appear in Brief as well as Full: dropping them is how a lapse gets written up as a
price loss.
Full — on request
Emit assets/loss-review-record.md verbatim — Bottom Line, timeline, cause split, detection,
classification, five whys, savability and attribution, the one fix, model feedback, win-back,
Assumptions and the seven-family Coverage Ledger. Cohort runs emit assets/cohort-rollup.md
instead, keeping the Assumptions table and the Coverage Ledger. Every field is populated or
written UNKNOWN — requires <source>; no row is dropped for having no data.
These fields have no valid empty value and no valid default. A record missing one is not returned:
Label on the decision, never the churn or renewal date (R24, R1); print the inference rule wherever it was inferred
decision_process_score and competitive_score, 0–5 each, each with its markers listed
Both scored on every record. A competitive score claimed without a dated economic-buyer marker is regenerated at zero, and competitive-displacement is refused below 3
active_decision_evidence — the dated events proving a decision was actually run
Empty means the renewal lapsed: code from the no-decision family, never other, never undetectable
decision_owner_vacancy_days
Computed from the timeline, not recalled. UNKNOWN is printed as "no decision owner was ever identified"
earliest_detectable_signal + date + holding system + alert status
The four lags, and the identity recognition + realised = detection
failure_mode · savability verdict + sub-code
Assigned by the facilitator, never by the account owner
One systemic fix — owner, date ≤90 days, backtest, "not doing" line
R17. A competitive fix is refused where decision-process ≥3 and competitive ≤1
Assumptions table · Coverage Ledger across all seven families
A concrete consequence per row; confidence never above the coverage cap (R23)
The Bottom Line block is emitted before any timeline, and carries these rows verbatim:
<A / B / C / D> — · Green at T−90? <Yes → scoring defect, routed to health-score-designer / No>
Systemic fix
— — by · Confidence <High/Medium/Low> ()
An exit interview is emitted below the divider, formatted for an email client, with no unfilled
placeholders — rules in ../cs-context/references/customer-voice.md. The firewall (R18) is
absolute: health score, risk band, ARR at risk, exposure, forecast category, save play, war room,
coverage tier, the two scores above, champion-departure inferences, competitor intelligence and any
assessment of a named person never appear, in any wording.
════════════════════════════════════════════════════════════
CUSTOMER-FACING — copy the block below and send as written.
Everything above this line is internal. Do not forward it.
════════════════════════════════════════════════════════════
```text
Subject: 20 minutes on what we got wrong at Northwind
Hi Dana,
Northwind came off the platform on 31 August, and I'd like to understand
that decision properly rather than guess at it. I run customer success
operations here, so this isn't a save attempt — the contract is closed.
The thing I want to get right: the intercompany reconciliation work you
raised in March never got finished. I want to know whether that decided it
or whether it was already decided by then.
Twenty minutes, no recording unless you'd prefer one. Thursday 11 September
or Friday 12th — and if you'd rather not, that's completely fine, with no
follow-up either way.
Thank you for three years, and for pushing us on the audit log — that
shipped because of you.
Priya
```
Variants by recipient, the question set and the debrief: `assets/exit-interview-guide.md`.
Quality Bar
All five dates recorded; labelled on the decision date, with the inference rule stated where inferred; opt-out deadline printed and the save window computed
Involuntary churn, quasi-churn and re-papering ruled out before any narrative was written; timeline covers T−540 → T−0 across all seven families, unretained families printed as such, every event tagged Observed/Inferred and known-at-the-time/known-only-now
Stated reason, proximate cause and root cause are three separate rows; the stated reason is verbatim, attributed to a named role, with the date and how it was asked
earliest_detectable_signal, earliest_detectable_date, the holding system and alert status all recorded; detection, recognition, realised-lead and action lags computed, and the identity holds
Failure mode assigned from the six-value list and the fix matches the mode; "Green at T−90?" answered, and a Yes routed as a scoring defect whatever the reason code
C16 — decision-process and competitive scores both printed, 0–5, each with its dated markers, in Brief as well as Full; decision_owner_vacancy_days computed; the decision test ran before any competitor was named
C16 — where the timeline holds no decision event the record is coded no-decision, deprioritised, budget-freeze, orphaned-renewal or budget-loss, never other and never failure mode undetectable; competitive-displacement carries a replacement confirmed by two independent sources and a competitive score ≥3, or it is stored as competitor_claimed
No competitive fix (battlecard, enablement, price response) proposed where decision-process ≥3 and competitive ≤1; the fix names a decision owner, a calendar gate or an approval path instead
Taxonomy populated from the closed vocabulary; origin stage coded separately from where it surfaced; five whys terminate on a cause we own, with the stop rule named
Savability assigned by someone other than the account owner; A+B and C+D shares reported separately, and attribution weights sum to 100 naming functions and mechanisms, never individuals
Exactly one primary fix, with owner, date ≤90 days, a backtest and a "not doing" line; no weight or threshold change on fewer than 3 corroborating records
Brief emitted by default; Full only on request; composite dollar figures rounded to two significant figures
Every number carries a provenance tag with a date or window, and every inference states its rule
Assumptions table present with a concrete consequence per row; Coverage Ledger carries history-retention depth per family and confidence ≤ the cap
Customer-facing text, where present, sits in a fenced block below the divider, with no placeholders and no internal language
Anti-Patterns
Anti-pattern
Correction
Copying the exit-survey answer into primary_reason, or dating the loss on the churn or renewal date
Code from the timeline and record the stated reason separately; label on the decision date, because the renewal date is the notice period, not the decision
"They left for price"
The most over-reported stated reason. Test it against usage, value evidence and what they bought instead
One cause per loss, or a timeline that starts 90 days out
primary_reason plus secondary_reason; T−540, or you find the symptom and miss the origin
Grading the team on facts discovered afterwards
Tag known-at-the-time vs known-only-now; only the former counts toward detection lag
No detection lag because nobody recorded when it was flagged
Reconstruct the flag date from the risk record, the forecast-category change, or the first internal message naming the account
Five whys that terminate on a person, or on headcount
Redirect to the system that permitted the decision; headcount is a budget argument, not a root cause
"Lessons learned" with no owner, or a list of eight fixes
One fix, one owner, a date inside 90 days, a backtest (R17)
Re-weighting the model on a single loss
≥3 records with the same failure mode before any weight, threshold or lead-time change
Coding a lapse as other, or as a competitive loss because a rival was mentioned once
The renewal that nobody decided is a first-class cause with its own fix: no-decision, deprioritised, budget-freeze, orphaned-renewal, budget-loss. competitive-displacement needs a replacement confirmed twice and a competitive score ≥3
Sending the fix to competitive enablement when the loss was decision-process
Score the two axes separately. Decision-process ≥3 with competitive ≤1 refuses a battlecard and buys a named decision owner, a calendar gate and a pre-wired approval path
Writing "the champion left" and stopping there
orphaned-renewal asks the next question: who inherited the decision, and on what date did we find out nobody had. decision_owner_vacancy_days is computed, and UNKNOWN means we never knew who decided
Reviewing a quarter account by account, or weighting the reason mix by count
Group by cause and weight by ARR — large losses have different causes from small ones
Attribution written as blame, or >60% of losses coded "not savable"
Function and mechanism only, and the facilitator is not the losing CSM; report A+B and C+D separately and defend the split
Skipping the post-mortem on a large downsell, or asking the customer at the cancellation screen
Quasi-churn above 75% reduction is a loss wearing a renewal's clothes; ask 2–4 weeks after the effective date, and not from the account owner
Related Skills
Skill
Relationship
cs-context
Run first. Segment boundaries, activation event, notice periods, source inventory
churn-risk · health-score-designer
The forward-looking twin consumes the lead times, signals and thresholds produced here; the score designer receives every Green-at-T−90 record as a scoring defect — those records are its calibration set
renewal-forecast · voice-of-customer
Receive realised loss rates and reason codes (next quarter's base rates), and the corrected reason behind the verbatims they supplied
cs-data-audit · exec-retention-review
Gate, then consumer: without decision_date this skill degrades to reasons only; the exec review takes the controllable/uncontrollable split and the ARR-weighted reason mix
Receive first-renewal losses coded origin_stage = onboarding; the trigger that fired too late or never fired; and unactioned findings, which are a capacity signal rather than a diligence one
Going Deeper
Read
When
references/root-cause-taxonomy.md
Coding any record — the thirteen values, the no-decision family and its scoring rubric, the reordered decision tree, mis-coding tells, churn_event extensions
references/timeline-reconstruction.md
Step 2 — per-source extraction, the event grammar, dating an unobservable decision, retention traps
1---2name: churn-postmortem3description: When a customer has churned, downgraded, or was nearly lost, and the user needs to know why it really happened, when it first became visible in data they already had, and what to change so the next one does not repeat. Also use when the user mentions 'what went wrong', 'accounts we lost', 'why did we lose', 'why did we lose them', 'churn post-mortem', 'loss review', 'post mortem on Acme', 'root cause analysis', 'we lost Northwind', 'they never renewed', 'churn reasons this quarter', 'could we have saved them', 'was it preventable', 'this account was green and churned', 'downgrade analysis', or 'quarterly churn review'. Use this whenever a loss has already happened and someone is trying to learn from it rather than relitigate it, even if they don't say 'post-mortem' — including a save that nearly failed. For live risk on an open account, see churn-risk. For feedback themes across the base, see voice-of-customer. For rebuilding the score this loss defeated, see health-score-designer.4license: MIT5---67# Churn Post-Mortem89You are running a loss review that changes what the company does next quarter. The subject is10**not the customer** — they decided and they are gone, and nothing you write moves them. The11subject is **us**: what we could have seen, when, and which of our systems, plays or12qualification rules let a knowable outcome arrive as a surprise.1314The rookie version is a sympathetic retelling: it copies the customer's exit answer into a reason15field, adds context that exonerates everybody, ends with "lessons learned", and is never read again.16It fails for three specific reasons — it treats a **stated reason** as a cause, it dates the loss on17the churn date rather than the date the decision was made, and it produces no change anyone owns.18The elite version separates stated reason from proximate cause from root cause, reconstructs a dated19timeline from every source, walks *backwards* to the first day the risk was visible in data we20already held, and returns one systemic fix with an owner and a due date. A post-mortem with no21systemic fix is a eulogy.2223The highest-value number here is the **detection lag** — the gap between the earliest date the loss24was detectable and the date anyone flagged it. It is the only output that directly tunes the risk25model, and it is almost always larger than the team assumes. Read26`../cs-context/references/evidence-standard.md` first: a post-mortem that invents a date is worse27than none, because the invented date becomes somebody's threshold.2829## Before Starting30311. **Read `.agents/cs-context.md`** (fallback `.claude/cs-context.md`) for segment boundaries,32 activation event, notice periods, source inventory and fiscal calendar. If absent, run33 `cs-context`; never ask what that file answers. Read34 `../cs-context/references/business-model-profiles.md` alongside it — a consumption business has35 no seat utilisation to decay and a self-serve product has no champion to depart, so the earliest36 detectable signal for the same loss sits in a different family.372. **Export before you analyse.** The commonest reason a post-mortem cannot be done is that the38 data was deleted at offboarding — product analytics, identity and support tools routinely purge39 deprovisioned orgs. Inside a deletion window, pull 18 months of history first.403. **Ask tappably, in one batch.** Use `AskUserQuestion`: 2–4 mutually exclusive options, the41 recommended one first, a line under each saying what it changes, at most four questions in one42 interruption. Never block — run the default, state it in the output's first line, record it in43 the Assumptions table.4445| # | Question | Options (recommended first) | What it changes | Asked when |46|---|---|---|---|---|47| 1 | **Scope** — what are we reviewing? | **This one loss (Recommended)** — full record, timeline, five whys, one fix · **A quarter's losses** — cohort patterns and reason mix by ARR · **A near-miss** — saved, or Green→Red in under 60 days · **Losses + material downsells** — adds contractions ≥20% ARR | Single-account depth vs cohort pattern-finding. The cohort run finds the systemic fix; the single run finds the missed signal | Always |48| 2 | **Customer input** — can we still talk to them? | **Yes — draft the interview request (Recommended)** — emits a customer-facing block · **Already spoken to them** — paste notes or transcript · **No contact possible** — data only; stated reason is capped at UNKNOWN | Whether the record has a stated-reason column at all, and whether customer-facing text is produced | Always |49| 3 | **Audience** — who reads this? | **CS leadership loss review (Recommended)** — full record, fix, model feedback · **Me and the account team** — timeline and detection lag only · **Exec staff / board appendix** — one page, dollars and the fix · **Product and Sales** — attribution and the qualification finding lead | Length, what leads, and how blunt the attribution section is | Always |50| 4 | **Materiality** | **Full churns + downsells ≥20% ARR (Recommended)** · **Full churns only** · **Everything, including seat reductions** | Which accounts enter a cohort run. A quarter reviewed on full churns only hides the contraction spiral | Cohort scope |51524. **Ask for the as-of date of every export**; never assume a file is complete or current. A churned53 account's usage table is often truncated at offboarding, manufacturing a cliff that was not there.545. **Accept whatever they have** — CSV, TSV, XLSX, JSON, NDJSON, warehouse results, a CRM55 closed-lost report, a pasted call transcript, a Slack thread, an email chain, screenshots56 described in prose, or a conversation when there is no file at all. Run57 `../cs-context/scripts/ingest.py` first on any supplied file: it sniffs encoding and delimiter,58 finds the real header row beneath export preamble, maps columns onto the canonical schema with59 a per-column confidence, normalises dates, money and booleans, and reports the join rate.60 **Confirm any mapping below 0.80 first** — `close_date` mapped onto `end_date` moves the whole61 timeline by a notice period.626. **Degrade, never refuse.** Partial history gives a partial record with a coverage figure and a63 confidence cap. The one stop condition is coverage under 40% of the seven families *and* no64 decision date: name the gap, give the timeline you can, assign no root cause.6566## How This Skill Works6768### Output mode — Brief by default6970| Mode | Length | When |71| --- | --- | --- |72| **Brief** (default) | ≤20 lines | Always, unless asked for depth |73| **Full** | The complete Output Template | Asked for it · the record goes into a loss review, a board appendix or a model change · someone will challenge the attribution |7475Brief is the answer written first — root cause, detection lag, savability, the one fix with an76owner and a date — not a summary written after Full. It drops the **display** of the reasoning,77never the reasoning, and obeys every evidence rule.7879### The rules this skill enforces8081Named rules from `../cs-context/references/operating-rules.md`, enforced in the output rather82than mentioned. A deviation is stated with its number, the circumstance, and what will be watched.8384| Rule | Enforced how |85| --- | --- |86| **R24** Label the decision, not the event · **R1** The opt-out calendar | `decision_date` is the label on every record, with the inference rule printed when it was not observed; the record also prints the opt-out deadline that governed and whether the decision landed before it |87| **R17** One play per account · **R14** The written skip | Exactly one primary systemic fix per loss, rejected fixes named rather than queued; losses not reviewed this cycle listed with a reason and a revisit date |88| **R22** Ordering before probability | No churn probability is stated; a threshold change ships only with a backtest, and composite dollar figures are rounded to two significant figures |89| **R23** The coverage cap | Coverage Ledger carries history-retention depth per family; confidence never exceeds it |90| **R18** The firewall · **R19** No date you do not own | Nothing from the record reaches the customer; the fix carries a date its named owner has agreed |9192**Four modes, one record.** Every mode populates the same closed-vocabulary fields on `churn_event`93— free-text churn reasons cannot be aggregated and therefore cannot be fixed.9495| Mode | Trigger | Scope | Produces |96|---|---|---|---|97| **Single loss** | Any full churn; any downsell ≥20% ARR; any quasi-churn (>75% reduction) | One account | Full record: timeline, cause split, detection lag, taxonomy, five whys, savability, attribution, one fix |98| **Near-miss** | A save that came within 30 days of notice; any Green→Red inside 60 days | One account | Same record; savability = saved. The detection lag is still the point |99| **Cohort / batch** | Quarterly, or across a renewal period | N losses | Reason mix by ARR, detection-lag and failure-mode distributions, repeat-cause register, instrumentation backlog |100| **Model feedback** | Once ≥8 records exist | Records, not accounts | Proposed signal weight, threshold and lead-time changes, each with a backtest |101102Two rules govern every mode: the record is facilitated by **someone other than the account owner**103(a losing CSM writing their own post-mortem produces a defence, not an analysis), and attribution104names **a function and a mechanism, never a person**. Run sequence: **dates → involuntary check →105timeline → stated / proximate / root → earliest detectable signal → **was a decision made?** →106taxonomy → five whys → savability + attribution → systemic fix → model feedback → (cohort roll-up).**107The decision test is never skipped and never runs after the competitor question.108109## Step 1 — Fix the dates, and label on the decision date110111Five dates, sometimes six months apart. Get this wrong and everything downstream fails silently:112a model trained on the wrong date learns the notice period.113114| Date | Definition | Field | Use |115|---|---|---|---|116| **Decision date** | When the buying committee actually decided | `churn_event.decision_date` | **The label.** Usually unrecorded — infer it and show the rule |117| Notice date | Notice served, or the opportunity moved to Closed Lost | `opportunity.stage_changed_at` | Best observed proxy when the decision cannot be inferred |118| Opt-out deadline | `renewal_date − notice_period_days` | `subscription.opt_out_deadline` | The clock we were actually racing. Print it even in hindsight |119| Effective date · service-off date | Service ended · access revoked | `churn_event.effective_date` | Finance and the ARR bridge only. Never a label |120121**Inferring the decision date** (state the rule, label it Inferred): the earliest of — auto-renew122switched off by the customer `[C1]`, a termination-terms or data-portability request `[R12]`, a123competitor named by an economic buyer `[R13]`, procurement re-engaged outside the renewal window124`[R11]`, a bulk admin export `[T6]`, or the meeting where they said it. Absent all of those, use125the notice date and say so — an inferred decision date caps confidence at Medium. Then print the126**save window we actually had** (`notice_date − decision_date`): a two-day window and a ninety-day127window are different failures with different fixes. Finally **rule out the misclassifications**,128before the narrative, or you will write a value essay about a failed credit card.129130| Check | Test | If it fires |131|---|---|---|132| **Involuntary** | `invoice.payment_failures > 0`, `payment_method_status` in `expired`/`removed`, and no cancel-intent event | Code `involuntary`; the fix is dunning and card-updater, not CS. Recurly's July 2026 network data puts SaaS median annual churn at 3.22% — 2.16% voluntary, 1.06% involuntary — but only 0.18% involuntary at $250+ ARPC `[M]`, so an *enterprise* involuntary loss is a billing-process defect worth its own record |133| **Quasi-churn** | ARR reduction >75% with the logo retained | Review it as a loss. A contraction this size hides inside GRR and never gets a post-mortem |134| **Merged / re-papered** | Same entity now billing under `parent_account_id` | Not churn. Correct the ARR bridge and stop |135| **Vendor-side error** | Cancelled by our own team for re-papering and never reinstated | Record it; the fix is a process fix, and it is embarrassing rather than strategic |136137## Step 2 — Reconstruct the timeline from every family138139One dated event stream, **T−540 → T−0**, T being the decision date. Walk all seven families; print140families with no retained history as "checked, no history retained" rather than dropping them.141142| Family | What you are looking for in hindsight |143|---|---|144| Product usage & adoption | The inflection in `usage_daily.core_actions`, the **buying team's own series** (not the aggregate), seat utilisation, breadth collapse, deprovisioning bursts, and whether the activation event ever fired |145| Commercial & contract | `auto_renew_changed_at`, seat reductions, term shortening, discount expiry, procurement and legal touches, competitor named, opportunity stage history |146| Relationship & engagement | Champion and sponsor departures (`contact.departed_at`, `email_status = hard_bounce`), multithreading depth over time, meeting acceptance, reply latency, and CSM changes on **our** side |147| Support & reliability | Escalations, P1 ageing, `ticket.reopened_count`, SLA breaches, and the ticket cluster that stopped without being resolved |148| Sentiment & VoC | Survey scores **with the respondent's role**, transcript sentiment, the sentence where someone first said the quiet thing |149| Billing & payment | Days-late trend against the account's own history, disputes, `payment_failures` |150| Firmographic & external | Acquisition, funding, layoffs, exec changes at their end, mandated consolidation |151152Two disciplines separate a timeline from a chronology: tag every event **Observed or Inferred** with153its rule, and **known-at-the-time or known-only-now**. Only known-at-the-time events are eligible154for Step 4 — otherwise you grade the team on information they did not have, which is how155post-mortems become theatre. Extraction per source: `references/timeline-reconstruction.md`.156157## Step 3 — Separate stated reason, proximate cause and root cause158159Three rows. They are rarely the same, and collapsing them is the defining rookie error.160161| | Definition | Tier | Data about |162|---|---|---|---|163| **Stated reason** | What the customer said, verbatim, with who said it and when | Observed — about a *conversation* | Them |164| **Proximate cause** | The dated event that turned a degrading account into a decision | Observed or Inferred | The account |165| **Root cause** | The vendor-side condition that made that event decisive, which we own and can change | Inferred, via Step 6 | **Us** |166167Only the third changes next quarter. **Exit answers mislead in a known direction** — correct the168bias rather than discounting the answer, which is still the only direct evidence of what they169experienced. Counter-questions for each: `references/root-cause-taxonomy.md`.170171| Bias | Direction of error | Correction |172|---|---|---|173| **Escape** — asked at the cancellation moment, they want out of the conversation | Over-reports price and budget; under-reports "we never got it working" | Ask 2–4 weeks *after* the effective date. Lincoln Murphy: at cancellation "they'll tell you whatever they think you need to hear to just let them out" `[P]` |174| **Face-saving and relationship preservation** — naming our failure criticises their own vendor choice, and they may need a reference later | Over-reports "corporate decision", "budget" and "great product, wrong time" | Ask about the process, not the verdict, and not from the account owner. Clozd's argument for post-churn interviews is that the customer "no longer has a vested interest in maintaining a relationship" `[V]` |175| **Respondent** — whoever replies is the one still there and still fond of us | Under-reports sponsor departure and buyer disconnect | Target the economic buyer; record who answered and their role |176| **Reason-field** — the account owner fills the picklist to close the record cleanly | Over-reports price; under-reports anything reflecting on the account team | Code from the timeline, by the facilitator |177| **Recency** and **sampling** — the last bad thing dominates a 14-month decline, and only amicable churns answer | Over-reports the proximate cause; skews the quarter's mix | Timeline before interview; report response rate and the ARR coverage of the interviewed set |178179Triangulate three sources, per Murphy's method `[P]`: the **external reason** (what they said), the180**internal reason** (what the data shows), and the **context clues** (what they did). All three181agreeing earns High confidence; where they diverge, the divergence *is* the finding — record both.182183## Step 4 — Earliest detectable signal, and the detection lag184185The core forensic exercise. Work backwards from T−0 to the earliest date on which a reasonable186observer, using **only data that existed then**, could have called the account materially at risk.187188```189detection_lag_days = decision_date − earliest_detectable_date ← what we could have had190recognition_lag_days = first_flagged_date − earliest_detectable_date ← lost to detection191realised_lead_time = decision_date − first_flagged_date ← what we actually had192action_lag_days = first_intervention_date − first_flagged_date ← lost to routing and capacity193 detection_lag = recognition_lag + realised_lead_time (identity — check it)194```195196Record `earliest_detectable_signal` (an ID from `../cs-context/references/signal-library.md`),197`earliest_detectable_date`, **the system that already held the data**, and whether an alert198existed. Then classify the failure mode — each has a different owner and fix:199200| Failure mode | Test | Fix type | Owner |201|---|---|---|---|202| **Absent** | The event genuinely did not exist in any system | Emit the event | Product / data engineering |203| **Uninstrumented** | The raw data existed; no metric was computed from it | Add the metric to the schema | CS Ops |204| **Unalerted** | The metric existed; no threshold fired | Set or tune the threshold | CS Ops |205| **Unrouted** | The alert fired into a queue with no owner | Routing and ownership | CS leadership |206| **Unactioned** | Routed to a named owner who did not act in time | Play, capacity or prioritisation | CS leadership |207| **Undetectable** | No signal at any lead time (e.g. an acquisition announced and decided the same week) | None — record and stop. The fix is not detection | — |208209Then run the model's report card: **was this account Green at T−90?** If yes, the record is a210false negative of the health score and goes to `health-score-designer` as a scoring defect,211whatever the reason code says. Method, aggregates and backtest: `references/detection-lag.md`;212beyond about six records, `scripts/detection_lag.py`.213214## Step 5 — Was a decision made at all? Then classify215216Most renewals are lost to inertia, a reorg, a spend freeze or a champion who left with nobody217inheriting the file — not to a rival. A record that names a rival it cannot evidence routes the218fix to competitive enablement, the one place it cannot work. **The decision test therefore runs219before the competitor question, on every record.**220221**5a · Score both axes. Neither substitutes for the other, and both are printed.**222223| Axis | Score | Markers — 1 point each, every one needing a dated timeline event |224|---|---|---|225| **Decision-process** | 0–5 | `C13` renewal opportunity stalled in one stage ≥2× the segment's median cycle, or never opened · `C12` PO not issued or budget not allocated by T−30, or `F6` a spend freeze or new approval threshold · `F5`/`F2` reorg, dissolution or exec change that absorbed the sponsoring programme · `R1`/`R3` decision owner left and no successor was engaged · `Z1` no bilateral contact in the 60 days before `decision_date` |226| **Competitive** | 0–5 | `R13` a rival named by an **economic buyer**, dated · `R11` a re-bid, RFP or vendor comparison run by procurement · `R12` termination or portability request in the same window as a named alternative · the replacement confirmed by a **second independent source** · `C6` a concession demanded citing a named alternative's price |227228`decision_owner_vacancy_days` = `decision_date` − the last dated interaction with anyone holding229renewal decision authority. Computed on every record, never left to memory. **UNKNOWN is itself230the finding:** it means we never knew who decided.231232**5b · Three refusals, applied before a code is written.**233234| Refusal | Trigger | What happens instead |235|---|---|---|236| No competitive code without a confirmed destination | `competitive-displacement` proposed with competitive < 3, or no replacement confirmed by two independent sources | Store the claim as `competitor_claimed`, then re-walk the coding tree with the competitor evidence excluded — a stalled opportunity read as "they were evaluating" is decision-process, not competitive |237| No competitive fix on a decision-process loss | Decision-process ≥ 3 **and** competitive ≤ 1 | The Step 8 fix addresses the decision process — a named decision owner, an opt-out-calendar gate (`R1`), a pre-wired approval path. Battlecards, competitive enablement and price response are refused |238| No `other`, no `undetectable`, for a lapse | The timeline holds no decision event at all | Code `no-decision`, `deprioritised`, `budget-freeze`, `orphaned-renewal` or `budget-loss` — whichever the timeline evidences. A lapse always has an antecedent — a stalled opportunity, an unissued PO, a vacant decision owner — so `undetectable` is unavailable |239240**5c · The closed taxonomy.** One `primary_reason`, zero or more `secondary_reason`, three241orthogonal axes. Definitions, the reordered decision tree, mis-coding tells:242`references/root-cause-taxonomy.md`.243244| Axis | Values |245|---|---|246| `primary_reason` — **no-decision family, walked first** | `no-decision` · `deprioritised` · `budget-freeze` · `orphaned-renewal` · `budget-loss`. Five first-class causes with their own root-cause branches and their own fixes — never an "other" bucket |247| `primary_reason` — the rest | `lack-of-adoption` · `product-value-gap` · `product-quality` · `sponsor-loss` · `corporate-decision` · `competitive-displacement` · `involuntary` · `other` |248| `secondary_reason` (many) | Same vocabulary |249| **Locus** | `vendor-controllable` · `jointly-controllable` · `customer-internal` · `market` — only the first two generate systemic fixes; the rest generate qualification changes |250| **Origin stage** | `sales-qualification` · `onboarding` · `adoption` · `value-realisation` · `renewal-execution`. **Where it originated is almost never where it surfaced**, and coding both is what makes the data useful |251| **Impact** | `full-churn` · `tier-downgrade` · `seat-churn` · `quasi-churn` — maps to `churn_event.type` |252253Two governance rules: `other` above 15% of records means the taxonomy needs a new category, not254that reality is messy; and a reason is coded only from timeline evidence — where the timeline255disagrees with the stated reason, code the timeline and record the disagreement.256257## Step 6 — Five whys, on the vendor-side chain258259Asking "why did the customer leave?" five times produces five restatements of the churn reason.260Ask **"why did we not prevent it?"** Every answer must be a fact from the timeline, not a theory.2612621. **Stop when you reach a cause you own and can change.** That is the root.2632. **Stop before "we should hire more CSMs."** That is a budget argument, not a root cause.2643. **When an answer names a person's mistake, redirect one level** — ask what system permitted that265 decision. Blameless is not politeness: a chain terminating on a human terminates on something you266 cannot fix (Google's SRE postmortem practice is the reference discipline `[P]`). Worked chain and267 a bank of terminations: `references/systemic-fixes.md`.268269## Step 7 — "Was it savable?" and cross-functional attribution270271Four verdicts with required sub-codes, assigned by the facilitator, not the account owner.272273| Verdict | Definition | Sub-codes | Fixes | Owning function |274|---|---|---|---|---|275| **A — Should never have been sold** | The requirement was never in scope, or the account sat outside the ICP at signature | `outside-icp` · `unscoped-requirement` · `no-real-champion` · `discount-bought-fit` | ICP definition, qualification, deal-desk gates | Sales / RevOps |276| **B — Not savable, exogenous** | Acquisition, shutdown, budget eliminated, mandated consolidation | `acquired` · `shutdown` · `budget-eliminated` · `mandated-consolidation` | Nothing. Track the rate | CS Ops (reporting only) |277| **C — Savable, we did not see it** | The signal existed in data we already held and nobody saw it in time | `absent` · `uninstrumented` · `unalerted` · `unrouted` | Detection: instrumentation, thresholds, routing | CS Ops / data |278| **D — Savable, we saw it and it did not work** | Flagged in time; the play failed, ran too late, or was too small | `unactioned` · `play-insufficient` · `capacity` · `vendor-failure` | Play design, capacity, product or process | CS leadership + owning function |279280**The honesty check.** A book where more than 60% of losses are coded A or B is either badly281qualified or dishonestly coded `[P]`. Report A+B and C+D separately: A+B is a strategy and282qualification number, C+D a CS execution number, and mixing them lets each hide behind the other.283Then attribute across functions with weights summing to 100 — function and mechanism, never a284person — with a **"seen before?"** count of prior post-mortems carrying the same attribution: a285cause on its third appearance is not a cause, it is an unshipped fix.286287## Step 8 — One systemic fix, and the model feedback288289Exactly one primary fix per loss — a list of eight fixes is a list of none.290291| Requirement | Rule |292|---|---|293| Addresses the **failure mode**, not the symptom | An `unalerted` loss gets a threshold, not a training session |294| Named owner, not the most junior person in the room, and a due date ≤ 90 days | Owner is a function lead; longer than a quarter and the fix will not survive the next reorg |295| Matches the **higher of the two Step 5 scores** | Decision-process ≥3 with competitive ≤1 refuses a competitive fix and ships a decision-process one: a named decision owner on the account, a T−180 opt-out-calendar gate (`R1`), or a pre-wired approval path with procurement |296| Validation stated, and a "not doing" line | Backtest against the last N losses **and a control set of renewals**, so the change is tested for false positives; naming the rejected fix stops it being re-proposed every quarter |297298**Never re-weight on N=1** (`R22`). A single loss may add a signal to a watch list; a weight,299threshold or lead-time change needs ≥3 records with the same failure mode. Emit the change set300with current value, proposed value, evidence count, backtest, owner and due date.301302## Step 9 — Cohort mode: find the pattern, not N stories303304Each record compresses to one row and the artifact becomes the ten-table pattern report in305`assets/cohort-rollup.md`, whose first table is the decision-process/competitive split. Weight the reason mix **by ARR, not by count**: count-weighting hides306that large losses have different causes from small ones. **The no-decision family and307`competitive-displacement` are reported as two separate ARR shares before any reason table** —308a quarter whose competitive share exceeds its no-decision share is a coding tell, not a market309finding, and `scripts/detection_lag.py` computes and flags the split. Backdrop for whether the quarter's rate is310a process or a market problem — median GRR was 84% on full-year 2025 actuals, down from 88%, top311quartile 91%, bottom quartile 76% (Aleph × Benchmarkit *2026 SaaS & AI Performance Benchmarks*, 342312companies, 226 reporting GRR) `[M]`. The repeat-cause register is read first.313314## Output Template315316### Brief — the default317318```markdown319**<Account> · decided <date> · $<X>k ARR lost · `<primary_reason>`**320321**Root cause:** <one clause, vendor-side, something we own.>322**Decision-process <n>/5 · competitive <n>/5.** <The higher axis, the markers behind it, and the323decision owner's vacancy in days — or that we never knew who held the decision.>324**Detection lag: <N> days.** <Signal> was visible in <system> on <date>; first flagged <date>.325Failure mode: <mode>.326**Savable:** <A/B/C/D> — <one sentence, including what a save would have cost.>327**Fix:** <owner> — <action> — by <date>. Validation: <backtest>.328<Only if true:> **Green at T−90 — this is a scoring defect, routed to `health-score-designer`.**329330Confidence: <level> (<n>/7 families, history retained to <date>).331*Full record, timeline, attribution and coverage ledger on request.*332```333Round composite figures to two significant figures — **$310k**, not $312,400 (`R22`). The two334scores appear in Brief as well as Full: dropping them is how a lapse gets written up as a335price loss.336337### Full — on request338339Emit `assets/loss-review-record.md` verbatim — Bottom Line, timeline, cause split, detection,340classification, five whys, savability and attribution, the one fix, model feedback, win-back,341Assumptions and the seven-family Coverage Ledger. Cohort runs emit `assets/cohort-rollup.md`342instead, keeping the Assumptions table and the Coverage Ledger. Every field is populated or343written `UNKNOWN — requires <source>`; no row is dropped for having no data.344345**These fields have no valid empty value and no valid default. A record missing one is not returned:**346347| Required field | The rule that makes it non-empty |348|---|---|349| `decision_date` + basis · opt-out deadline · `save_window_days` | Label on the decision, never the churn or renewal date (`R24`, `R1`); print the inference rule wherever it was inferred |350| **`decision_process_score` and `competitive_score`**, 0–5 each, each with its markers listed | Both scored on every record. A competitive score claimed without a dated economic-buyer marker is regenerated at zero, and `competitive-displacement` is refused below 3 |351| `active_decision_evidence` — the dated events proving a decision was actually run | Empty means the renewal lapsed: code from the no-decision family, never `other`, never `undetectable` |352| `decision_owner_vacancy_days` | Computed from the timeline, not recalled. `UNKNOWN` is printed as "no decision owner was ever identified" |353| `earliest_detectable_signal` + date + holding system + alert status | The four lags, and the identity `recognition + realised = detection` |354| `failure_mode` · savability verdict + sub-code | Assigned by the facilitator, never by the account owner |355| One systemic fix — owner, date ≤90 days, backtest, "not doing" line | `R17`. A competitive fix is refused where decision-process ≥3 and competitive ≤1 |356| Assumptions table · Coverage Ledger across all seven families | A concrete consequence per row; confidence never above the coverage cap (`R23`) |357358**The Bottom Line block is emitted before any timeline, and carries these rows verbatim:**359360| | |361|---|---|362| ARR lost | $X (<full churn / quasi-churn / downgrade>) · tenure <N> months · renewal number <N> |363| Decision date | <date> (Observed / Inferred — rule) · notice <date> · effective <date> |364| Opt-out deadline that governed | <date> — decided <N> days <before/after> it · save window <N> days |365| **Was a decision made?** | <**Yes** — evidence: <dated events> / **No — the renewal lapsed**, coded `<no-decision family value>`> |366| **Decision-process vs competitive** | **<n>/5** — <markers> · **<n>/5** — <markers> · decision-owner vacancy <N> days |367| Stated reason · root cause | "<verbatim>" — <name, role, date, how asked> → <one clause, vendor-side> |368| **Detection lag** | **<N> days** — detectable <date>, flagged <date> · failure mode <absent / uninstrumented / unalerted / unrouted / unactioned / undetectable> |369| Savable | <A / B / C / D> — <sub-code> · Green at T−90? <Yes → scoring defect, routed to health-score-designer / No> |370| Systemic fix | <fix> — <owner> — by <date> · Confidence <High/Medium/Low> (<criteria met>) |371372An exit interview is emitted below the divider, formatted for an email client, with no unfilled373placeholders — rules in `../cs-context/references/customer-voice.md`. The firewall (`R18`) is374absolute: health score, risk band, ARR at risk, exposure, forecast category, save play, war room,375coverage tier, the two scores above, champion-departure inferences, competitor intelligence and any376assessment of a named person never appear, in any wording.377378````379════════════════════════════════════════════════════════════380CUSTOMER-FACING — copy the block below and send as written.381Everything above this line is internal. Do not forward it.382════════════════════════════════════════════════════════════383384```text385Subject: 20 minutes on what we got wrong at Northwind386387Hi Dana,388389Northwind came off the platform on 31 August, and I'd like to understand390that decision properly rather than guess at it. I run customer success391operations here, so this isn't a save attempt — the contract is closed.392393The thing I want to get right: the intercompany reconciliation work you394raised in March never got finished. I want to know whether that decided it395or whether it was already decided by then.396397Twenty minutes, no recording unless you'd prefer one. Thursday 11 September398or Friday 12th — and if you'd rather not, that's completely fine, with no399follow-up either way.400401Thank you for three years, and for pushing us on the audit log — that402shipped because of you.403404Priya405```406Variants by recipient, the question set and the debrief: `assets/exit-interview-guide.md`.407````408409## Quality Bar410411- [ ] All five dates recorded; labelled on the **decision date**, with the inference rule stated where inferred; opt-out deadline printed and the save window computed412- [ ] Involuntary churn, quasi-churn and re-papering ruled out before any narrative was written; timeline covers T−540 → T−0 across all seven families, unretained families printed as such, every event tagged Observed/Inferred **and** known-at-the-time/known-only-now413- [ ] Stated reason, proximate cause and root cause are three separate rows; the stated reason is verbatim, attributed to a named role, with the date and how it was asked414- [ ] `earliest_detectable_signal`, `earliest_detectable_date`, the holding system and alert status all recorded; detection, recognition, realised-lead and action lags computed, and the identity holds415- [ ] Failure mode assigned from the six-value list and the fix matches the mode; "Green at T−90?" answered, and a Yes routed as a scoring defect whatever the reason code416- [ ] **`C16`** — decision-process and competitive scores both printed, 0–5, each with its dated markers, in Brief as well as Full; `decision_owner_vacancy_days` computed; the decision test ran before any competitor was named417- [ ] **`C16`** — where the timeline holds no decision event the record is coded `no-decision`, `deprioritised`, `budget-freeze`, `orphaned-renewal` or `budget-loss`, never `other` and never failure mode `undetectable`; `competitive-displacement` carries a replacement confirmed by two independent sources and a competitive score ≥3, or it is stored as `competitor_claimed`418- [ ] No competitive fix (battlecard, enablement, price response) proposed where decision-process ≥3 and competitive ≤1; the fix names a decision owner, a calendar gate or an approval path instead419- [ ] Taxonomy populated from the closed vocabulary; origin stage coded separately from where it surfaced; five whys terminate on a cause we own, with the stop rule named420- [ ] Savability assigned by someone other than the account owner; A+B and C+D shares reported separately, and attribution weights sum to 100 naming functions and mechanisms, never individuals421- [ ] Exactly one primary fix, with owner, date ≤90 days, a backtest and a "not doing" line; no weight or threshold change on fewer than 3 corroborating records422- [ ] Brief emitted by default; Full only on request; composite dollar figures rounded to two significant figures423- [ ] Every number carries a provenance tag with a date or window, and every inference states its rule424- [ ] Assumptions table present with a concrete consequence per row; Coverage Ledger carries history-retention depth per family and confidence ≤ the cap425- [ ] Customer-facing text, where present, sits in a fenced block below the divider, with no placeholders and no internal language426427## Anti-Patterns428429| Anti-pattern | Correction |430| --- | --- |431| Copying the exit-survey answer into `primary_reason`, or dating the loss on the churn or renewal date | Code from the timeline and record the stated reason separately; label on the decision date, because the renewal date is the notice period, not the decision |432| "They left for price" | The most over-reported stated reason. Test it against usage, value evidence and what they bought instead |433| One cause per loss, or a timeline that starts 90 days out | `primary_reason` plus `secondary_reason`; T−540, or you find the symptom and miss the origin |434| Grading the team on facts discovered afterwards | Tag known-at-the-time vs known-only-now; only the former counts toward detection lag |435| No detection lag because nobody recorded when it was flagged | Reconstruct the flag date from the risk record, the forecast-category change, or the first internal message naming the account |436| Five whys that terminate on a person, or on headcount | Redirect to the system that permitted the decision; headcount is a budget argument, not a root cause |437| "Lessons learned" with no owner, or a list of eight fixes | One fix, one owner, a date inside 90 days, a backtest (`R17`) |438| Re-weighting the model on a single loss | ≥3 records with the same failure mode before any weight, threshold or lead-time change |439| Coding a lapse as `other`, or as a competitive loss because a rival was mentioned once | The renewal that nobody decided is a first-class cause with its own fix: `no-decision`, `deprioritised`, `budget-freeze`, `orphaned-renewal`, `budget-loss`. `competitive-displacement` needs a replacement confirmed twice and a competitive score ≥3 |440| Sending the fix to competitive enablement when the loss was decision-process | Score the two axes separately. Decision-process ≥3 with competitive ≤1 refuses a battlecard and buys a named decision owner, a calendar gate and a pre-wired approval path |441| Writing "the champion left" and stopping there | `orphaned-renewal` asks the next question: who inherited the decision, and on what date did we find out nobody had. `decision_owner_vacancy_days` is computed, and UNKNOWN means we never knew who decided |442| Reviewing a quarter account by account, or weighting the reason mix by count | Group by cause and weight by ARR — large losses have different causes from small ones |443| Attribution written as blame, or >60% of losses coded "not savable" | Function and mechanism only, and the facilitator is not the losing CSM; report A+B and C+D separately and defend the split |444| Skipping the post-mortem on a large downsell, or asking the customer at the cancellation screen | Quasi-churn above 75% reduction is a loss wearing a renewal's clothes; ask 2–4 weeks after the effective date, and not from the account owner |445446## Related Skills447448| Skill | Relationship |449| --- | --- |450| `cs-context` | **Run first.** Segment boundaries, activation event, notice periods, source inventory |451| `churn-risk` · `health-score-designer` | The forward-looking twin **consumes** the lead times, signals and thresholds produced here; the score designer **receives** every Green-at-T−90 record as a scoring defect — those records are its calibration set |452| `renewal-forecast` · `voice-of-customer` | **Receive** realised loss rates and reason codes (next quarter's base rates), and the corrected reason behind the verbatims they supplied |453| `cs-data-audit` · `exec-retention-review` | Gate, then consumer: without `decision_date` this skill degrades to reasons only; the exec review takes the controllable/uncontrollable split and the ARR-weighted reason mix |454| `onboarding-plan` · `proactive-outreach` · `book-of-business-triage` | **Receive** first-renewal losses coded `origin_stage = onboarding`; the trigger that fired too late or never fired; and `unactioned` findings, which are a capacity signal rather than a diligence one |455456## Going Deeper457458| Read | When |459| --- | --- |460| `references/root-cause-taxonomy.md` | Coding any record — the thirteen values, the no-decision family and its scoring rubric, the reordered decision tree, mis-coding tells, `churn_event` extensions |461| `references/timeline-reconstruction.md` | Step 2 — per-source extraction, the event grammar, dating an unobservable decision, retention traps |462| `references/detection-lag.md` · `references/systemic-fixes.md` | "Could we have caught it?" — method, the463464…(truncated)
Run npx skillmds@latest add gaintrace/churn-postmortem in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
When a customer has churned, downgraded, or was nearly lost, and the user needs to know why it really happened, when it first became visible in data they already had, and what to change so the next one does not repeat. Also use when the user mentions 'what went wrong', 'accounts we lost', 'why did we lose', 'why did we lose them', 'churn post-mortem', 'loss review', 'post mortem on Acme', 'root cause analysis', 'we lost Northwind', 'they never renewed', 'churn reasons this quarter', 'could we have saved them', 'was it preventable', 'this account was green and churned', 'downgrade analysis', or 'quarterly churn review'. Use this whenever a loss has already happened and someone is trying to learn from it rather than relitigate it, even if they don't say 'post-mortem' — including a save that nearly failed. For live risk on an open account, see churn-risk. For feedback themes across the base, see voice-of-customer. For rebuilding the score this loss defeated, see health-score-designer. It is listed under Coding & Dev Tools on SkillMD.
This skill has not completed SkillMD's automated safety review yet. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free. This skill is licensed under MIT.
gaintrace (@gaintrace) published this skill. Their other Agent Skills are listed on their SkillMD profile.