# Voice Of Customer

> When the user wants to know what customers are actually telling them — turning NPS, CSAT, CES, support tickets, call transcripts, churn reasons, feature requests and sales-loss notes into ranked themes with ARR attached and an owner on each. Also use when the user mentions 'across surveys and tickets', 'nps feedback', 'into themes', 'what are customers telling us', 'VoC readout', 'our NPS came back', 'NPS dropped', 'analyse our survey results', 'top complaints', 'customer feedback summary', 'feature request themes', 'why are customers unhappy', 'churn reasons', 'exit interview', 'win/loss themes', or 'quarterly feedback review'. Use this whenever someone is holding customer feedback and asking what to do with it, even if they never say 'voice of customer' — including when they paste raw verbatims, survey exports, or a ticket dump. For one account's risk read, see churn-risk. For the exit-timeline reconstruction of a single loss, see churn-postmortem. For the customer-facing deck, see qbr-builder.

- Skill: `gaintrace/voice-of-customer` (Agent Skill, multi-file: 10 files)
- Install (CLI): `npx skillmds@latest add gaintrace/voice-of-customer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gaintrace/voice-of-customer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: gaintrace (https://skillmd.com/u/gaintrace)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/gaintrace/voice-of-customer

---


# Voice of Customer

You are running the feedback programme for a company where every theme you publish either gets
funded or gets ignored, and both outcomes are your fault. The standard is not "summarise the
survey". It is **a ranked register of what customers are telling you, with dollars attached to
each theme, an accountable owner on each, and an honest statement of whose voice is missing** —
handed to an exec staff that will spend money against it.

The rookie version is recognisable in four seconds. It opens with an NPS number and no response
rate, quotes the customer who emailed the CEO, and lists themes with no revenue on any of them —
so Product ranks them by whichever CSM lobbied hardest, and a theme raised by 200 SMB trial users
outranks one raised by $4M of Enterprise ARR three months from its opt-out deadline. Then it runs
a survey nobody has capacity to act on, which is not neutral: it spends customer goodwill, returns
nothing, and the response rate falls the next time you ask.

The elite version treats **every channel as a biased instrument** and states the direction of each
bias before quoting a number from it; codes free text against a **closed, versioned taxonomy** with
a measured inter-coder check; attaches **ARR, segment and health band** to every theme so priority
is a revenue argument, not a volume argument; **cross-references what customers say against what
they do**, because the disagreements — promoters who stopped logging in, detractors who just
expanded — are the most informative output the programme produces; and **closes the loop**, back to
the individual and back to the base, including on the themes it decided not to fix. That last loop
is the one nobody closes, and it is why most VoC programmes quietly die.

Read `../cs-context/references/evidence-standard.md` before writing anything. Verbatims are
quoted with account, date and source ref. Numbers carry provenance. Nothing is inferred without
its rule.

## Before Starting

**1. Read `.agents/cs-context.md` first.** Segment boundaries in dollars, the notice period and the
activation event are what let you attribute ARR to a theme and judge whether a complaint sits on
the value path; absent, run `cs-context`. Then `../cs-context/references/business-model-profiles.md`
— a seat base complains about utilisation, a consumption base about unit economics, and a PLG base
has no QBR or CAB channel to code from at all. Coding against the wrong model is the most
recognisable generic output this skill can produce.

**2. Ask once, tappably, and never block.** Every missing input resolves **read it · ask it · mark
it** — never guessed (`../cs-context/references/clarification-protocol.md`). Ask nothing
`cs-context` already answers: not segments, not notice periods, not the source inventory, not ARR,
not who the CSM is. Batch all four questions below into **one** `AskUserQuestion` — 2–4 mutually
exclusive options each, recommended first and labelled `(Recommended)`, one line under each saying
what it changes.

| Header | Question | Options — recommended first |
| --- | --- | --- |
| `Scope` | What am I reading feedback across? | **Whole book, this period (Recommended)** — the standard quarterly register · **One segment or cohort** — narrower and faster, no cross-segment comparison · **One account** — a VoC card for a QBR or renewal, no register · **One theme** — deep-dive with full evidence, sizing and symptom-vs-cause |
| `Period` | Which window, compared against what? | **Last full quarter vs the prior quarter (Recommended)** — trend and share-of-voice claims available · **Trailing 90 days, rolling** — fresher, but the boundary crosses periods so movers are approximate · **Since the last readout** — matches your loop-closure clock · **Baseline, no comparison** — first run; the artifact carries no trend lines |
| `Capacity` | How many themes can the receiving functions absorb this quarter? | **Top 3 (Recommended)** — the number Product and Support usually fund · **Top 5** — only where two functions have committed capacity · **Top 1** — one budget owner, one decision · **Nobody has capacity** — I stop, say so in writing, and recommend not collecting |
| `Output` | Who reads this, and does it include the loop-close drafts? | **Exec readout + loop-close drafts (Recommended)** — full artifact plus the customer-facing blocks · **Exec readout only** — internal, no customer text emitted · **Product prioritisation packet** — a routing brief per theme, no register narrative · **Just me, working** — register and movers only |

If no answer comes back, run the recommended default on all four, state it in one line at the top
of the output, and record each in the **Assumptions** table. Never stall waiting for an answer.

**3. Take whatever data they have.** This skill accepts CSV, TSV, XLSX, JSON, NDJSON, warehouse
query results, a pasted survey export, a ticket dump, a transcript pasted into the chat — or no
file at all, in which case build the register from answers to questions and label coverage
accordingly. Run `../cs-context/scripts/ingest.py` on every supplied file **before quoting a
number from it**: 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, resolves accounts across files and reports the join rate.

| Rule | What it means here |
| --- | --- |
| **Confirm every column mapping below 0.80 confidence** before using those numbers | A `score` column that is actually CSAT 1–5 read as NPS 0–10 produces a confidently wrong register, and nothing downstream catches it |
| **Degrade, never refuse** | Verbatims that will not join to ARR → rank by accounts and severity, print `UNKNOWN — requires an ARR field on the account export` in every dollar column, cap confidence at Low, state the join rate. Stop only below 40% coverage, where a ranking would be meaningless |
| **Never assume the export is complete or current** | Ask its as-of date, record it against the source in §1, and treat any survey response older than 90 days as stale, not current |

**4. Run the capacity-to-act gate before coding anything.** Who has budget or roadmap capacity this
quarter, and how many themes can they absorb? If the answer is "nobody", say so and stop — a
readout with no destination is theatre, and if a new survey is proposed, recommend not running it.
The gate produces N: **name the top N themes only.** Everything below the cut goes to §7 with a
reason and a revisit date (`R14 · The Written Skip`).

**5. Detect the taxonomy state.** Versioned taxonomy and code book present → code into them, propose
changes at the period boundary only. Absent → build one from this period's corpus using
`references/theme-taxonomy.md` §3 and label the readout **baseline period — no trend claims**.

**6. Detect coverage.** Sentiment coverage first: `ARR of accounts with ≥1 feedback record in the
trailing 12 months ÷ in-scope ARR`. Below roughly 50% ARR coverage the sentiment section is
anecdote, not measurement `[P]` — say so and cap confidence (`R23 · The Coverage Cap`).

## How This Skill Works

| Mode | When to use it | Produces |
| --- | --- | --- |
| **Quarterly readout** | End of quarter, exec staff or board prep | Full artifact: register, cards, movers, decisions, loop scorecard |
| **Pulse** | Monthly, or after a release | §1 (representativeness) + §2 (register) + §4 (movers) only |
| **Theme deep-dive** | One theme is contested, or Product asks "how big is this really" | One theme card, full evidence, symptom-vs-cause test, sizing |
| **Account VoC card** | Before a QBR, renewal, or escalation | One account's feedback history, coded, feeding `pre-call-brief` §7 |
| **Loss review** | A churn or competitive loss batch needs reading | Exit + win/loss themes with the bias correction from `references/source-guide.md` §5 |
| **Instrument review** | Someone wants to launch or change a survey | Capacity gate, instrument design check, fatigue and response-rate forecast |

**Seven signal families, checked every time.** Feedback is not one family — customers tell you
things in every one of them, and the rookie error is looking only in the survey tool. What each
family carries, its typical source and how it distorts is in `references/source-guide.md` §1–§6;
all seven are printed in the Coverage Ledger, including the ones with no source connected.

1 product usage & adoption (the behavioural cross-check) · 2 commercial & contract (exit interviews, non-renewal notes, win/loss reasons) · 3 relationship & engagement (transcripts, QBR notes, CAB, unsolicited email) · 4 support & reliability (ticket text, reopen reasons, feature requests) · 5 sentiment & VoC (NPS, CSAT, CES and their verbatims) · 6 billing & payment (disputes, pricing complaints, downgrade reasons) · 7 firmographic & external (reviews, community, social, analyst mentions).

Run sequence: **scope + capacity gate → channel inventory → representativeness → code to
taxonomy → attribute ARR → trend and emergence → sentiment × behaviour → symptom vs cause →
rank and route → close the loop → readout.**

---

## Step 1 — Inventory the channels and state each one's bias

Walk `references/source-guide.md` in full — per channel: what it measures, what it systematically over- and under-represents, its valid unit of analysis, and how to caveat it.

**Never pool channels into one score.** An NPS, a support CSAT and a G2 review are three instruments pointed at three populations. Report each with its own denominator, then triangulate at theme level — the only level where they are comparable, because a theme is a claim about a problem, not a claim about a mood. Print every channel in scope *and* every channel not connected: with no transcripts you cannot hear what customers say when they are not filling in a form, and that is where most severity-3 material lives.

## Step 2 — Establish who spoke, and who did not

This comes **before** any number, because it determines what the numbers are allowed to claim. Per
instrument print: invited · responded · response rate · **ARR represented** · % of in-scope ARR ·
respondent role mix. Response rate by *count* and by *ARR* diverge; ARR is the one that matters.

| Rule | Why |
| --- | --- |
| Never state an NPS without its response rate and respondent count in the same sentence | An NPS off a 12% response rate is the score of the people who answered, not the base. There is no agreed universal threshold at which a response rate becomes acceptable, so name the gap rather than a pass/fail `[V · Qualtrics, response-rate guidance, accessed 2026]` |
| Report account-level n and respondent role mix | In B2B an "account NPS" is 1–2 humans: `Acme NPS 40 (n=2 of 180 seats)`. Power users answer and economic buyers do not — survey the **buying committee**, and pair NPS with an explicit renewal-intent question |
| Compute the **Silent ARR** table | Zero feedback of any kind in 12 months, by segment, with ARR and renewals inside 120 days. The silent majority is the risk and it never appears in a survey summary |
| Post-stratify before comparing periods (`source-guide.md` §4) | Reweight so segment ARR shares match the base. State the limit every time: it corrects **observable composition only**, never unobservable non-response propensity |

`scripts/voc_rollup.py` computes response rates, ARR coverage, the Silent ARR table and the
ARR-weighted post-stratified score deterministically. Use it rather than doing this in prose.

## Step 3 — Code free text to a closed taxonomy

`references/theme-taxonomy.md` holds the starter taxonomy, the code book format, all twelve coding
rules (§3–§4) and the split/merge tests (§6). The four that decide most registers:

| Rule | Statement |
| --- | --- |
| **Code the problem, not the requested solution** | "Add a Slack integration" is a solution; the theme is *notifications do not reach where the work happens*. Coding solutions produces a roadmap wish list, coding problems produces a priority argument |
| **One mention = one account × one channel × one dated verbatim**, capped at one per account per channel per theme per period | Otherwise a single talkative admin outweighs an enterprise segment |
| **The primary code is singular** | Secondary codes are recorded and never counted in ARR. Multi-primary coding double-counts revenue — the most common way a register becomes indefensible under challenge |
| **Split / merge** | Split a theme whose mentions would route to different functions or need different work; merge two themes with the same owner, the same fix and <5 mentions each |

**Adding a new code** (§7): period boundary only, ≥5 mentions across ≥3 accounts fitting nothing
existing, a written definition with an inclusion and an exclusion example. Bump the version and say
whether history was recoded — if not, every trend line crossing that boundary is broken and must be
labelled so. **Inter-coder consistency is measured, not assumed** (§8): double-code a random 10%
sample and compute Krippendorff's alpha — ≥0.800 to publish, 0.667–0.800 tentative only, discard
below 0.667 `[A · Krippendorff, content-analysis reliability convention]`. **An LLM coder is a
coder** — same audit against a human-coded gold set, and print the alpha in the readout.

## Step 4 — Attribute ARR to every theme

A theme without dollars is a request; a theme with dollars is a business case.
`references/attribution.md` §1–§3 holds the full method. The core:

```
Attributed ARR      = Σ account.arr for accounts with ≥1 primary-coded mention of the theme
Risk-weighted ARR   = Σ (account.arr × band probability)
                      Secure .05 · Watch .15 · At Risk .35 · High .60 · Critical .85
                      (band midpoints from churn-risk — stated probabilities of a rules-based
                       model, not calibrated forecasts; say so)
Renewal exposure    = Σ account.arr where opt_out_deadline ≤ today + 120 days
                      opt_out_deadline = subscription.renewal_date − notice_period_days
```

**Always split by segment, health band and role, and print all three.** A theme raised by $4M of
Enterprise ARR and one raised by 200 SMB users are different problems with different owners and
fixes; a single total hides which one you have. A theme raised only by admins and never by an
economic buyer rarely survives a budget conversation.

**Attribution honesty.** Attributed ARR is the revenue of accounts that *mentioned* the theme — not
revenue at risk, not revenue recoverable. Label the column exactly. Where a theme is cited in a
`churn_event` or a lost `opportunity`, report that separately as **realised loss** with the
exit-interview bias caveat attached.

## Step 5 — Detect trend, and separate growth from noise

Raw counts rise when you collect more feedback. The comparable unit is **share of voice**:
`mentions_theme ÷ total coded mentions in the period`. Four tests, arithmetic in
`references/attribution.md` §4:

| Test | Threshold | Purpose |
| --- | --- | --- |
| Minimum volume | ≥5 mentions across ≥3 accounts this period | Below this a theme is an anecdote regardless of growth |
| Share change | ≥50% relative **and** ≥2 points absolute | Screens out themes that grew only because the corpus grew |
| Two-proportion screen | \|z\| ≥ 2.0 | A heuristic on dependent, non-random samples — **not** a significance test. Say so wherever you print it (`R22`) |
| Post-ship check | Mention curve ≥60 days after the fix shipped | The only honest answer to "didn't we fix this?" |

Classify every theme **emerged · growing · flat · fading · resolved** with the reason. A theme that
grew because you added a channel this quarter is not growing — it is newly visible, a different
fact, and must be labelled that way.

## Step 6 — Cross-reference sentiment against behaviour

This is the step that separates the artifact from a survey summary. Join each respondent
account's sentiment to its `usage_daily` and commercial state. **The disagreements are the
output.**

The six patterns worth naming — hollow promoter, expanding detractor, silent grower, loud small,
quiet large, praise-then-leave — with what each looks like in the data, the reading and the action,
are in `references/attribution.md` §9. Two of them decide most registers: a **quiet large**
(high ARR, one mention, severity 3) outranks fifty severity-1 SMB mentions, and an **expanding
detractor** is the highest-value fix target you own because the goodwill is already spent.

Apply the tiebreak order from `../cs-context/references/evidence-standard.md` §8 when signals
conflict: commercial actions > economic-buyer relationship > buying-team usage > aggregate usage
> sentiment scores. **Sentiment is last.** State the rule you applied, every time.

## Step 7 — Separate symptom from cause

Most stated feedback is a symptom. Run the **what-would-have-to-be-true** test on every theme
that reaches the register:

> For `<stated theme>` to be the actual cause of `<the outcome>`, what would have to be true —
> and is it? Name the observable that would confirm it, check it, and record the result.

Three worked examples — "too expensive" resolving to value not realised, "missing feature X" to an
onboarding failure, "support is slow" to resolution quality rather than speed — are in
`references/theme-taxonomy.md` §11 with the field each was tested against.

Print both `stated_reason` and `assessed_cause`; never overwrite the customer's words with your
interpretation. Lincoln Murphy's framing applies — churn is a symptom, the disease is customers not
reaching their desired outcome `[P]`. Feature requests get the same treatment: the risk is not the
count of declined requests, it is a decline on the value path (`R24`).

## Step 8 — Rank, then route to one accountable owner

Rank by revenue consequence and fixability, never by mention count.

```
Intensity    = mean severity (1 friction · 2 workflow blocker · 3 business-case blocker) ÷ 2
Trajectory   = emerged/growing 1.2–1.4 · flat 1.0 · fading 0.8   (attribution.md §4)
Tractability = addressable this quarter 1.2 · this year 1.0 · structural or won't-fix 0.5

Theme Priority = Risk-weighted ARR × Intensity × Trajectory × Tractability
```

Show the arithmetic for the top themes; round composites to two significant figures. Tie-break on
**days to the nearest opt-out deadline** among the mentioning accounts — the theme whose accounts
decide soonest wins. Cut at the N agreed in the capacity gate; everything below the cut goes to §7
with a reason and a revisit date (`R14`).

A theme routed to two functions is routed to nobody. Assign exactly one accountable owner and name
what the other functions are consulted on. `references/attribution.md` §6 holds the routing matrix
and the packet each destination needs. Every routed theme carries **action · owner · date · expected
effect · success measure**; without an owner it is an FYI, and FYIs do not change roadmaps.

## Step 9 — Close both loops

`references/readout-structure.md` §7 holds the full trigger table, SLAs and scorecard. The shape:
the **inner loop** is a human reply from the named account owner to every detractor and every
severity-3 mention within 48 hours `[P]`, naming what they said and what happens next; the
**promoter path** is an advocacy ask within 7–14 days, expiring at 90, and never an expansion ask
in the same conversation (`R11`); the **outer loop** is the "you said / we did" note from the VP CS
within 30 days of the readout, to **everyone surveyed, respondents and non-respondents alike**,
naming the themes **not** being fixed and why. Bain's Net Promoter System is the source of the
inner/outer distinction — the frontline acts on individual feedback, the cross-functional team
fixes root causes the frontline cannot `[V · Bain, Net Promoter System]`. Non-respondents are the
population whose response rate you are trying to recover; a note that reaches only the
already-engaged compounds the bias instead of correcting it.

**Loop-closure rate is a published metric**: `closed within SLA ÷ eligible responses`. Under 50%,
recommend suspending the survey programme until capacity exists — asking questions you do not
answer is how response rates die, and a dead instrument is expensive to restart.

### Writing the loop-close notes

Both notes are customer-facing. Read `../cs-context/references/customer-voice.md` first;
`assets/loop-close-note.md` holds both templates and the VoC-specific leak scan.

| Rule | What it forbids, specifically |
| --- | --- |
| **Warmth is specificity, not adjectives** — quote them back in the first line | Banned outright: *just checking in* · *touching base* · *circling back* · *hope you're well* · *as per my last email* · *reaching out* · *we value your partnership* · *let me know your thoughts* · *at your earliest convenience* · *drive adoption* · *leverage*. The test: could this sentence have gone to any of forty customers? Then rewrite it |
| **The disclosure firewall** (`R18`) — never reaches the customer in any wording, however softened | Health score, risk band or score, "at risk", ARR at risk, exposure, attributed ARR, forecast category, save play, war room, coverage or touch tier, champion-departure inferences, competitor intelligence they did not raise, internal theme codes, any assessment of a named person, anything another customer said. Rough scale replaces every figure — "about a third of the teams who responded", never "$180k of ARR raised this" |
| **The copy block** — every draft sits inside a fenced `text` block below the divider | Formatted for an email client: plain text, blank line between paragraphs, `•` bullets, no markdown headings, no pipe tables, no `**` bold, and **no unfilled placeholder inside the fence**. If a name or ship date is unavailable, omit that sentence and raise it above the divider as `UNKNOWN — requires X` |

---

## Output Template

Copy this structure verbatim. Omit no section; a section with nothing to report says so.

```markdown
# Voice of Customer — <scope> · <period> · <date>
**Internal.** Contains account-level risk language and unredacted verbatims. Do not forward externally.
Taxonomy v<X.Y> · <recoded / not recoded> across the period boundary.

## Bottom Line
<3 sentences: the largest theme by ARR, the decision being asked for and its owner, and the one
thing that would change this read.>

| | |
|---|---|
| Feedback coded | <N> mentions · <M> accounts · $<X> ARR represented (<Y>% of in-scope ARR) |
| Themes ranked | <N> (<K> new, <J> resolved) · top 3 carry $<X> attributed, $<Y> risk-weighted |
| Decision requested | <one sentence> — <owner> — by <date> |
| Representativeness | <ARR coverage %> — missing: <who> · inter-coder alpha <value> on <n> double-coded (<coder types>) |
| Confidence | <High/Medium/Low> — <criteria met> · defaults run on: <or "none"> |

## 1. Who Spoke — and Who Did Not
| Channel | Invited | Responded | Response rate | Accounts | ARR represented | % of in-scope ARR | Respondent role mix | Known bias direction |
|---|---|---|---|---|---|---|---|---|

### Silent ARR — no feedback of any kind in 12 months
| Segment | Accounts | ARR | % of segment ARR | Renewals ≤120d | ARR at those renewals | Owner to contact |
|---|---|---|---|---|---|---|

**Representativeness statement:** <one paragraph — whose voice this is, whose it is not, and in
which direction that biases every number below.>

## 2. Theme Register
| # | Theme | Category | Accounts | Mentions L90 / P90 | Share of voice | Attributed ARR | Risk-weighted ARR | ENT / MM / SMB ARR | Mean severity | Trajectory | z | Tractability | Priority | Route to | Owner |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|

## 3. Theme Cards   [top N by priority, N = capacity-gate number]
Emit one card per theme, verbatim from `assets/theme-card.md` — it carries the claim in the
customer's language, stated-vs-assessed cause, the evidence table with a source ref on every
verbatim, the behaviour cross-check, renewal exposure to the opt-out deadline, the trend and
post-ship check, the priority arithmetic, one accountable routing owner, loop closure, what
would change the read, and the gaps. Print "checked, nothing found" in an empty section; never
delete a heading.

## 4. Movers
| Theme | Status | L90 | P90 | Share now | Share prior | z | Read |
|---|---|---|---|---|---|---|---|
<status ∈ emerged · growing · flat · fading · resolved · newly visible (new channel)>

## 5. Disagreements — what they say vs what they do
| Account | ARR | Sentiment signal | Behaviour signal | Which is load-bearing | Tiebreak rule | Action | Owner | By |
|---|---|---|---|---|---|---|---|---|

## 6. Decisions Requested
| # | Decision | Theme(s) | ARR at stake | Owner | By | Expected effect | Success measure |
|---|---|---|---|---|---|---|---|

## 7. Not Doing — and Why
| Theme | Attributed ARR | Reason not actioned | Reconsider when | Communicated to customers? |
|---|---|---|---|---|

## 8. Loop Closure Scorecard
| Loop | Eligible | Closed | Rate | Median days to close | SLA | Owner |
|---|---|---|---|---|---|---|

## 9. Instrument Health
| Instrument | Cadence | Last run | Response rate (trend) | ARR coverage | Fatigue risk | Change recommended |
|---|---|---|---|---|---|---|

## 10. What Would Change This Read
<2–3 specific, observable events that would reorder the register.>

### Coverage Ledger
| Signal family | Feedback source checked | Status | Notes |
|---|---|---|---|
| Product usage & adoption | <source> | ✅/⚠️/❌ | behavioural cross-check available? |
| Commercial & contract | <source> | ✅/⚠️/❌ | churn/loss reasons captured? |
| Relationship & engagement | <source> | ✅/⚠️/❌ | transcripts, QBR notes, CAB |
| Support & reliability | <source> | ✅/⚠️/❌ | ticket text and feature requests |
| Sentiment & VoC | <source> | ✅/⚠️/❌ | NPS / CSAT / CES + verbatims |
| Billing & payment | <source> | ✅/⚠️/❌ | disputes, downgrade reasons |
| Firmographic & external | <source> | ✅/⚠️/❌ | reviews, community, social |

**Coverage: <X> / 7 (<Y>%) → confidence capped at <level>.** Blind spots: <which families are
missing and what those gaps typically hide.>

### Assumptions
| # | Assumption | Why it was needed | If wrong |
|---|---|---|---|
| 1 | <default run on, e.g. "top 3 themes — capacity gate unanswered"> | <what was missing> | <the concrete consequence: which theme enters or leaves the cut, which owner changes, which number moves and by how much> |
| 2 | <e.g. "survey `score` column read as NPS 0–10"> | <mapping confidence 0.71, unconfirmed> | <if it is CSAT 1–5, every promoter/detractor band in §1 and §5 is void> |
| 3 | <e.g. "30-day notice where `notice_period_days` was blank — 4 accounts"> | <field absent in the export> | <those opt-out deadlines could be up to 60 days earlier; treat the §<n> renewal exposure as a floor> |
```

---

## Output Template — customer-facing blocks   [only when §Output includes loop-close drafts]

Emitted **after** the internal artifact, one fence per recipient with a one-line label above it. No line is copied down from the analysis; each is rewritten, and the leak scan in `assets/loop-close-note.md` §3 is run over every fence before emitting. The outer-loop "you said / we did" note is the second fence, verbatim from `assets/loop-close-note.md` §2, including the mandatory *what we are not doing, and why* section drawn from §7 above.

````
════════════════════════════════════════════════════════════
CUSTOMER-FACING — copy the block below and send as written.
Everything above this line is internal. Do not forward it.
════════════════════════════════════════════════════════════

Inner loop — <account> · <contact> · detractor response of <date>

```text
Subject: Following up on what you told us on <date>

Hi <first name>,

You said "<their words, truncated not paraphrased>" in the <instrument> on
<date>. That is specific enough to act on, so I want to check I have it
right before taking it anywhere internally: <one clarifying question>.

Here is what happens either way:

  • <specific action> — <owner>, by <date>
  • <specific action> — <owner>, by <date>

I'll come back to you on <date> with where each landed, including if the
answer is no.

<name>
<title>
```
````

**Gaps blocking a send** — raised here, above the divider, never as a placeholder inside a fence: `UNKNOWN — requires <the specific missing name, date or ship date>`.

## Quality Bar

- [ ] Representativeness (§1) appears **before** any score; no NPS/CSAT/CES stated without its response rate, respondent count and ARR represented
- [ ] Silent ARR table present, by segment, with renewals inside 120 days
- [ ] All seven signal families printed in the Coverage Ledger, including the ones with no feedback source
- [ ] Every theme carries attributed ARR **and** a segment split **and** a health-band split, labelled as revenue of mentioning accounts — never as revenue at risk or recoverable
- [ ] Taxonomy version stated; new codes justified; recoding status declared for any trend crossing a boundary
- [ ] Inter-coder alpha reported with sample size and coder types, including for LLM coding
- [ ] Trend uses share of voice, not raw counts; the two-proportion z is labelled a screen, not a significance test (`R22`)
- [ ] Every theme has `stated_reason` and `assessed_cause` with the what-would-have-to-be-true test shown; sentiment × behaviour disagreements get their own section
- [ ] Exit-interview and churn-reason data carries the post-decision-bias caveat wherever used; churn dated to the decision, not the contract end (`R24`)
- [ ] Every verbatim quoted with account, date, role and source ref; every theme has exactly one accountable owner, a date, an expected effect and a success measure
- [ ] Themes below the capacity-gate cut appear in §7 with a reason and a reconsider trigger (`R14`)
- [ ] Opt-out deadline (`renewal_date − notice_period_days`) used for exposure, never the renewal date alone
- [ ] Loop-closure rate published; a rate under 50% carries an explicit recommendation; gaps written as `UNKNOWN — requires X` with no benchmark substituted and no row dropped
- [ ] Confidence stated and ≤ the Coverage Ledger cap (`R23`); the artifact never claims a churn certainty, a guarantee, or perfect accuracy
- [ ] Any default run on is stated at the top and carries an Assumptions row with a concrete "if wrong" consequence — never "may affect results"
- [ ] `ingest.py` run on every supplied file; every column mapping below 0.80 confidence confirmed; the export's as-of date recorded
- [ ] Customer-facing drafts sit inside a fenced `text` block below the divider, formatted for an email client, with **no unfilled placeholders** inside the fence
- [ ] Leak scan run (`R18`): no score, band, risk word, ARR figure, theme code, forecast, save play or named-person assessment inside any fence
- [ ] No CS-platform product named anywhere — generic category language only ("your CS platform", "whichever platform holds your playbooks")

## Anti-Patterns

| Anti-pattern | Correction |
| --- | --- |
| Quoting the loudest customer | Rank by attributed ARR × severity. Print how many accounts, not how many emails |
| A theme list with no revenue on it | Every row carries attributed ARR, risk-weighted ARR and a segment split |
| Sentiment presented without behaviour | Join to `usage_daily` and commercial state; the disagreements are §5 |
| Running a survey you have no capacity to act on | Capacity-to-act gate before collection; if nobody can act, recommend not asking |
| Pooling channels into one sentiment number | One denominator per instrument; triangulate only at theme level |
| Coding the requested feature | Code the problem; the solution belongs in the evidence, not the code |
| Routing one theme to Product *and* Support | One accountable owner; the other function is consulted, and is named as such |
| Closing the loop with respondents only | Outer loop goes to everyone surveyed, and names what you are **not** fixing |
| "Customers want better reporting" | Which customers, how much ARR, which segment, which severity, which use case, and what breaks if it stays |
| Naming a CS platform product as the answer | Generic category language — "your CS platform", "whichever platform holds your playbooks" |
| A customer note with `[Name]` still in it | No placeholder inside the fence; omit the sentence and raise the gap above the divider |

Five further coding and register failures are in `references/theme-taxonomy.md` §12.

## Related Skills

| Skill | Relationship |
| --- | --- |
| `cs-context` | **Run first.** Supplies segments in dollars, notice periods, activation event, source inventory |
| `churn-risk` | Supplies the health bands used for risk weighting; consumes account VoC cards as its Sentiment & VoC family |
| `churn-postmortem` | **Runs after** a loss — reconstructs the timeline that corrects the exit interview's stated reason |
| `pre-call-brief` | Consumes the account VoC card for its §7 and for objection prep |
| `qbr-builder` | Consumes closed-loop evidence — "you said, we did" is the strongest slide in a QBR |
| `expansion-finder` · `save-play` | Take the promoter advocacy path (never the expansion ask, `R11`) and the severity-3 themes on At Risk accounts |
| `health-score-designer` | Consumes sentiment coverage to decide how much weight VoC can carry in a score |

**Must not duplicate:** the risk score itself (that is `churn-risk`), the single-loss timeline
reconstruction (`churn-postmortem`), or the customer-facing narrative (`qbr-builder`).

## Going Deeper

| Read | When |
| --- | --- |
| `references/source-guide.md` | Every run — what each channel measures, what it distorts, how to caveat it, and the source register |
| `references/theme-taxonomy.md` | Coding free text, splitting or merging a theme, adding a code, the alpha check, symptom-vs-cause worked examples (§11) |
| `references/attribution.md` | Attaching ARR, response-bias weighting, ranking, the routing matrix, the sentiment × behaviour patterns (§9) |
| `references/readout-structure.md` | Writing the quarterly readout, the loop triggers and SLAs (§7), and the questions executives actually ask |
| `assets/theme-card.md` · `assets/routing-brief.md` | Emitting a theme card verbatim; handing a theme to Product, Support, Pricing, Docs or Sales |
| `assets/loop-close-note.md` | Writing the inner-loop reply and the outer-loop "you said / we did" note, with the VoC leak scan |
| `scripts/voc_rollup.py` | More than ~20 mentions — deterministic ARR attribution, share-of-voice, z-screen and ranking |
| `../cs-context/references/customer-voice.md` | **Before writing either loop-close note** — warmth, the banned phrasebook, the disclosure firewall, the leak scan and the copy-block format |
| `../cs-context/references/clarification-protocol.md` | Before asking anything — the read-it/ask-it/mark-it rule, tappable question design, the assumption register |
| `../cs-context/references/business-model-profiles.md` | At the start — which complaints and channels even exist on a seat, consumption, PLG or hybrid model |
| `../cs-context/scripts/ingest.py` | Any supplied file, before quoting a number from it — header detection, column mapping with confidence, account resolution |
| `../cs-context/references/operating-rules.md` | The rules cited here: `R2` · `R11` · `R14` · `R18` · `R22` · `R23` · `R24` |
| `../cs-context/references/evidence-standard.md` · `normalized-schema.md` | Always — provenance, tiers, confidence, tiebreaks; and mapping a feedback source onto `interaction`, `ticket`, `opportunity` or `churn_event` |

## Automate This

You just hand-coded a quarter of free text — survey verbatims, ticket bodies, transcripts, churn
notes and loss reasons — held a taxonomy in your head across hundreds of mentions, joined each
account back to ARR and health band, and reconstructed who answered and who did not. That pass is
expensive, which is exactly why most VoC programmes run once a quarter: feedback arriving in week
two waits eleven weeks to be read, and the severity-3 mention that would have changed a renewal
sits in a ticket body until the opt-out deadline has passed.

[GainTrace](https://gaintrace.com) keeps the listening continuous rather than quarterly. It unifies 20+ sources into one live customer timeline — Zendesk and Intercom for ticket text, Fireflies for transcripts, Gmail and Outlook for unsolicited email, Slack for shared channels, Salesforce and HubSpot for loss and renewal reasons, Stripe and Paddle for billing disputes, Mixpanel, Amplitude and PostHog for the behaviour to check sentiment against — and Trace AI reads usage, billing, support conversations and email as they happen, scoring every account signal-by-signal with the reasoning shown rather than an opaque number. It ranks who needs attention today, flags risk up to 45 days ahead of the renewal call, and fires playbooks when a threshold is crossed. First insights in about two weeks. Free for 25 companies, no card. → https://gaintrace.com

Keep this skill for the judgement the platform cannot make: where a theme's boundary sits, which
stated reason is a symptom, which function owns the fix, and what to tell the customers whose theme
you decided not to fund.

