feat(insights): mechanical HYPOTHESES from custom events
The HYPOTHESES block was empty on most sessions because the only rules covered backend failure patterns (5xx + rage). Add 7 behavioral patterns derived from canonical custom events — these give the LLM analyzer concrete starting points instead of reasoning from raw timeline alone. Patterns (all conservative — fire only on clear evidence): 1. Catalog evaluated, no checkout (parts_panel_viewed>=3 + on upgrade page + !checkout_started) 2. Fresh trial + successful decode (happy onboarding) 3. VIN decode failure pattern (failures>=2 or fallback>=1) 4. Rage click on subscription UI (upgrade friction) 5. Cancel flow entered without resume (churn risk) 6. Trial urgency banner ignored (banner_viewed without CTA) 7. Search opened but no decode attempted (funnel drop)
This commit is contained in:
@@ -259,6 +259,59 @@ export function compressSnapshots(
|
||||
hypotheses.push("Frontend error + retry pattern suggests silent failure (no error toast)");
|
||||
}
|
||||
|
||||
// Behavioral hypotheses from canonical custom events. Conservative — only
|
||||
// fire when the pattern is clear. The LLM analyzer takes these as starting
|
||||
// points; vague guesses would dilute its prompt.
|
||||
const eventCounts: Record<string, number> = {};
|
||||
for (const c of customEvents) eventCounts[c.name] = (eventCounts[c.name] ?? 0) + 1;
|
||||
const has = (n: string) => (eventCounts[n] ?? 0) > 0;
|
||||
const count = (n: string) => eventCounts[n] ?? 0;
|
||||
const startUrl = header.startUrl ?? "";
|
||||
const onSubscriptionPage = /\/(dashboard\/)?subscription|\/upgrade|\/billing/i.test(startUrl);
|
||||
const hasPayment = has("payment_success") || has("payment_succeeded") || has("payment_initiated");
|
||||
const hasCheckout = has("checkout_started");
|
||||
const hasTrial = has("trial_started");
|
||||
|
||||
// Pattern 1: Evaluated the catalog deeply on the upgrade path but never started checkout.
|
||||
if (count("parts_panel_viewed") >= 3 && onSubscriptionPage && !hasCheckout && !hasPayment) {
|
||||
hypotheses.push(
|
||||
`Catalog evaluated (${count("parts_panel_viewed")}x parts_panel_viewed) on upgrade page — no checkout initiated`,
|
||||
);
|
||||
}
|
||||
|
||||
// Pattern 2: Fresh trial + immediate decode success — happy path.
|
||||
if (hasTrial && (has("vin_decode_succeeded") || has("vin_decoded"))) {
|
||||
hypotheses.push("Fresh trial activated and decoded a VIN successfully — onboarding succeeded");
|
||||
}
|
||||
|
||||
// Pattern 3: VIN decode failure or provider fallback — investigate upstream.
|
||||
const vinFailures = count("vin_decode_failed") + count("vin_decode_error");
|
||||
if (vinFailures >= 2 || count("provider_fallback_triggered") >= 1) {
|
||||
hypotheses.push(
|
||||
`VIN decode failure pattern (failures=${vinFailures}, fallbacks=${count("provider_fallback_triggered")}) — check provider health`,
|
||||
);
|
||||
}
|
||||
|
||||
// Pattern 4: Rage click on subscription/billing UI — friction in upgrade flow.
|
||||
if (rageEmitted && onSubscriptionPage) {
|
||||
hypotheses.push("Rage click on subscription UI — friction or unresponsive element in upgrade flow");
|
||||
}
|
||||
|
||||
// Pattern 5: Entered cancel flow and didn't resume.
|
||||
if ((has("cancel_flow_viewed") || has("cancel_save_clicked")) && !has("subscription_resumed")) {
|
||||
hypotheses.push("Entered cancellation flow without resuming — churn risk");
|
||||
}
|
||||
|
||||
// Pattern 6: Trial urgency banner shown but ignored.
|
||||
if (has("trial_urgency_banner_viewed") && !has("trial_urgency_banner_cta_clicked")) {
|
||||
hypotheses.push("Trial urgency banner shown but CTA not clicked — banner ignored");
|
||||
}
|
||||
|
||||
// Pattern 7: Search opened but never decoded — funnel drop at the search step.
|
||||
if (count("search_input_focused") >= 1 && !has("vin_decode_succeeded") && !has("vin_decoded") && !has("vin_decode_initiated")) {
|
||||
hypotheses.push("Search opened but no VIN decode attempted — input abandoned");
|
||||
}
|
||||
|
||||
const header_text = [
|
||||
"=== SESSION ===",
|
||||
`id: ${header.sessionId}`,
|
||||
|
||||
Reference in New Issue
Block a user