# Voc Synthesize

> Cross-reference profiled VoC signals across every connected source and surface only patterns confirmed by multiple independent channels. Clusters by meaning using parallel subagents, then applies the confirmation rule in code. Outputs a confidence-ranked theme list with verbatim quotes and account context preserved. Trigger on /voc-synthesize, "what patterns are confirmed", "synthesize this week's signals".

- Skill: `aatirs-vault/voc-synthesize` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aatirs-vault/voc-synthesize`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aatirs-vault/voc-synthesize/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Aatirs-Vault (https://skillmd.com/u/aatirs-vault)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aatirs-vault/voc-synthesize

---


# /voc-synthesize — Cross-Source Pattern Detection

One mention is an anecdote. Three mentions across three different channels is a pattern. That
distinction is the entire product, and this skill is built so it cannot be quietly relaxed.

**Clustering is a judgment task, so subagents do it. Counting is not, so code does it.** The
confirmation rule lives in `scripts/synthesize.js` reading `config/thresholds.json`, and nowhere
else. If you find yourself reasoning about whether something "feels confirmed," you have left the
rule behind.

## Requires

| What | Value |
|---|---|
| Input | `outputs/voc/profiled/*.json`, plus the call analysis and review briefs |
| Config | `config/thresholds.json` |
| Cost | Subagent tokens. Five clustering agents per run. |

---

## Phase 1 — Gather

Collect everything in the window (default from `windows.default_days`):

| Source | Path |
|---|---|
| Profiled signals | `outputs/voc/profiled/*.json` |
| Call intelligence | `outputs/calls/analysis/call-intelligence-*.md` |
| Review briefs | `outputs/voc/sources/reviews/brief-*.json` |
| Chat, notes, CRM, surveys, tickets | `outputs/voc/sources/<channel>/*` |

**Do not read the quarantine folder.** Tier-U signals are excluded by design.

Report which sources were empty. A source that returned nothing because its connector is broken
looks identical to a source where nothing happened, and the difference matters — say which you
believe it was and why.

---

## Phase 2 — Cluster in parallel

Spawn one subagent per dimension, **all in a single message**:

`pain` · `request` · `praise` · `objection` · `competitive`

Each subagent receives the full corpus and returns clusters for its dimension only:

````
Group signals in the corpus below into themes for the "<dimension>" dimension.

Cluster on underlying meaning, not wording. "Export is slow", "downloads time out"
and "can't get data out for big events" are ONE theme. Err toward merging: two
themes that should have been one is a worse error than one theme that should have
been two, because splitting hides frequency.

Return ONLY this JSON:
{"clusters":[{
  "theme": "short specific name, written as the customer would recognize it",
  "dimension": "<dimension>",
  "signals": [{"channel":"...","weight_tier":"...","company":"...",
               "date":"YYYY-MM-DD","verbatim":"exact quote","source_file":"..."}]
}]}

Rules:
- Copy verbatim quotes EXACTLY. Do not clean up grammar or trim for length.
- Every signal keeps its original channel and weight_tier. Do not reassign them.
- Do not invent signals to strengthen a cluster.
- A signal may appear in only one cluster within your dimension.
- If a quote is ambiguous between two themes, put it in the more specific one.
CORPUS:
[...]
````

Merge all five results into one `clusters.json`.

---

## Phase 3 — Apply the rule in code

```bash
node scripts/synthesize.js outputs/voc/synthesis/clusters.json
```

This writes `<date>-confirmed.json`, `<date>-watchlist.json`, `<date>-dropped.json` and prints
the tally. It handles four things you should not re-derive by hand:

- **Independent source means distinct channel.** Two calls are one source.
- **Tier U never counts** toward confirmation, but is reported per theme so you can see how much
  unattributed volume sits behind it.
- **One tier-A signal alone never confirms.** Seniority is not corroboration.
- **A theme where every mention comes from one account gets downgraded**, because one loud
  customer is not a market pattern. This is the check most VoC tooling omits, and it is the one
  that most often prevents a bad roadmap decision.

Take the script's output as fact. Do not re-rank it because a dropped theme seemed interesting.

---

## Phase 4 — Write the report

`outputs/voc/synthesis/<date>-synthesis.md`:

```markdown
# VoC Synthesis — week of <range>

## Coverage
| Channel | Signals | Status |
|---|---|---|
| Calls | N | ok |
| Reviews | N | ok |
| Chat | 0 | connector not configured |
...
**Quarantined (unattributed):** N signals excluded from all counts.

## Confirmed themes
### <Theme name>
**High confidence** · N mentions · N channels (call, review, chat) · N accounts · tiers A:1 B:4
**First seen** YYYY-MM-DD · **Most recent** YYYY-MM-DD

> "verbatim quote"
> — Company, YYYY-MM-DD (call, tier A)

<3-5 quotes>

**What this means:** <one sentence, concrete, naming who should do what>

## Medium confidence
<same shape>

## Watchlist
<single-channel themes, one line each, with the channel named>

## What did not confirm
<count, plus two or three notable near-misses and what they were short of>
```

Lead with the confirmed themes. Put coverage above them so nobody reads a thin week as a
complete picture.

---

## What this gets wrong

- **The rule is a heuristic, not a truth test.** Three channels can all reflect one loud market
  segment. Check the account spread the script reports before acting.
- **Merging hides nuance.** Aggressive clustering is right for finding frequency and wrong for
  finding the specific edge case that is actually blocking deals. Read the raw quotes.
- **Absence proves nothing.** A theme that did not confirm may simply be one nobody asked about.
  Your discovery script shapes this corpus more than you think.
- **Recency bias is built in.** A weekly window favours whatever happened this week. Run a
  quarterly window occasionally to see what has been steadily true.
- **The rule can be gamed by adding connectors.** Wiring up more channels makes confirmation
  easier, not truer. If you add sources, consider raising `min_independent_sources`.

