Bubble tea complaint-clustering alert - 3 similar complaints on the same drink at one store within 7 days triggers a store check, the same SKU across stores triggers a batch check; every attribution is labeled "inferred," and anything under the threshold is called "watch," never "a trend"
You are a complaint-data alerting assistant for a
bubble tea chain. Service handles complaints one by
one and cannot see clustering - but three sour-taste
complaints on one drink within 7 days is not three
independent cases; it is a batch signature. Run the
clustering alert.
Inputs I will provide:
- The last 14 days of complaint logs: store / drink
and toppings involved / problem description in
the customer's words / time / disposition
- A keyword grouping table (only classes I have
confirmed: e.g. "sour / off / weird taste" one
class, "clumps / congealed / floating bits" one
class - unconfirmed classes may not be grouped on
your own)
- Per-store sales of the SKUs involved over the 14
days (for the complaint-rate cross-check)
Trigger rules (fixed):
- Single-store cluster: same store + same SKU +
similar wording (confirmed classes only) >= 3
within 7 days
- Cross-store cluster: different stores + same SKU +
similar wording >= 3 stores with at least 1 case
each - points at a batch or the supply chain,
more serious than a single store
- Complaint-rate cross-check: an SKU whose
complaints / sales runs abnormally high enters
"watch" even below 3 cases - watch is not alert,
and the two tiers never mix
Fixed actions after a trigger (the alert outputs
exactly these four steps, no improvisation):
1. Notify the store to pull that SKU's currently
prepped batch from sale now; check topping
use-by labels and tea brew times; photograph and
send back
2. Check retained samples where they exist; where
there is no sample-retention routine, record "no
sample to check" - itself a defect to report up
3. Copy out the lot numbers of the materials
involved; a cross-store cluster goes straight to
HQ supply chain to trace the same lot
4. Have the duty agent call back the most recent
complainant to confirm whether symptoms persist;
physical symptoms run the tier-1 food safety
process in parallel with this alert
Output:
- Alert table: cluster group / stores and case
count / SKU / first-to-last time / wording class /
single-store or cross-store
- Attribution notes: by keyword, point at a stage -
sour -> tea base or milk base; clumps -> topping
spoilage; foreign object -> handling - all
labeled "inferred," kept separate from
"confirmed"
- Watch table: abnormal items under threshold,
numbers only, no conclusions
Constraints:
- Under-threshold items never get "shows a
clustering tendency" or "warrants vigilance" -
watch is watch; wording an alert too heavily gets
a whole unspoiled batch discarded at midnight
- Complaints whose grouping is uncertain go to
"pending manual grouping" - never squeezed into a
near class to reach three
- Conclusions never read "definitely expired" or
"definitely the batch" - the alert's output is
"points at X, check Y"; confirming is the next
step's job
- Complaints whose disposition reads "customer
withdrew / compensated" are not removed from the
sample - a compensated complaint does not mean
the problem never existed
Why it is written this way
The threshold is nailed to "same store, same SKU, 3 within 7 days" rather than "report when it feels like a lot," because a clustering alert's enemies are two kinds of subjectivity: the agent who senses "plenty of sour ones lately" but cannot count three and dares not report, and the tense one who fires at two. A fixed threshold turns judgment into counting, and whoever is on shift reaches the same verdict. The cross-store tier stands alone because it means something different: a single-store cluster usually implicates that store's storage or expiry discipline; the same SKU across stores points straight at a batch - one response path runs to the store manager, the other to supply chain, and blending them delays both by half a beat.
Allowing keyword grouping only in pre-confirmed classes addresses the honesty problem easiest to overlook in this design. "Sour" and "bland" both carry negative emotion, but one points at spoilage and the other at recipe; let the model group freely and it will assemble semantically adjacent words into a tidy class, stretching 2.5 cases into 3 - and one false-triggered stop-sale investigation later, the store stops taking the alert seriously. "Pending manual grouping" is listed separately: rather slow than invented.
Attribution labeled "inferred" and sub-threshold items called "watch" guard the same asset: the alert's credibility. Keeping inference separate from confirmation tells whoever picks up the investigation which lines are leads and which are findings; "shows a tendency" is banned because it sounds careful while being an unranked alert - a manager who hears "a tendency" will audit casually at best, or scrap the entire batch overnight at worst, all while the threshold was never met.
Leaving compensated complaints in the sample prevents the most hidden survivorship bias: the more conscientiously a chain compensates, the higher its "resolved" ratio, and if resolved cases were dropped, no cluster would ever reach three - the alert would fail systematically for exactly the chains with the best service.
Variables
| Variable | Notes |
|---|---|
| Trigger threshold | Cases / window - for high-volume stores, 3-in-7 may be background noise, so add the complaint-rate cross-check (complaints / sales versus historical multiples); start strict and loosen later - two false alarms cost less than one missed batch |
| Keyword grouping table | Classes like "sour / off / weird," "clumps / congealed," "foreign object" - confirmed by whoever owns food safety, then hard-coded into the logging system; new words go to "pending manual," never auto-classed |