Detection + quality gate
Every detector emits a typed signal; a scoring gate decides whether it is active (LLM-eligible) or watch (remembered, not diagnosed).
flowchart LR
subgraph Detectors["Signal Detectors (catalog)"]
D1["funnel_drop"]
D2["traffic_source"]
D3["device_gap"]
D4["product_performance"]
D5["search_opportunity"]
D6["data_health"]
D7["rage_click"]
D8["js_error"]
D9["slow_load"]
end
EV["Typed SignalEvidence
numerator / denominator
relativeDelta · CI
observationClass
persistenceRunCount"]
subgraph Gate["Signal-Quality Gate"]
F1["sampleAdequacy 35%"]
F2["effectVsMde 35%"]
F3["persistence 15%"]
F4["novelty 15%"]
MULT["× dataQualityMultiplier"]
SCORE["signalQualityScore [0,1]"]
end
ACTIVE["active
LLM-eligible"]
WATCH["watch
remembered, not diagnosed"]
TRUST["trust-class (data_health)
bypass → always active"]
D1 & D2 & D3 & D4 & D5 & D7 & D8 & D9 --> EV
D6 --> TRUST
EV --> F1 & F2 & F3 & F4
F1 & F2 & F3 & F4 --> MULT --> SCORE
SCORE -->|"≥ threshold"| ACTIVE
SCORE -->|"< threshold"| WATCH
style ACTIVE fill:#c8e6c9
style WATCH fill:#fff9c4
style TRUST fill:#b3e5fc
Stage 3b · Recording enhancement (optional)
For the top product-performance signal, recorded sessions are sampled and analyzed by the LLM for friction — only when data is reliable. This is the lightweight, inline path; the full replay analysis runs as a separate daily batch →.
flowchart LR
TOP["Top product_performance signal"] --> SAMPLE["Sample recorded sessions
on that URL"]
SAMPLE --> LLM["LLM: event-sequence
friction analysis"]
LLM --> SIG["session_recording_friction signals
URL-matched → cluster with product signal"]
SIG --> DB[(posthog_signals)]
style DB fill:#fff3e0,stroke:#FF9800
Signal lifecycle (Stage 4 expiration)
Signals are deduped on re-detection, harden from watch to active, and expire when not re-detected within the retention window.
stateDiagram-v2
[*] --> watch: score below threshold
[*] --> active: score above threshold or trust-class
watch --> active: re-detected, score rises
watch --> expired: retention elapsed
watch --> dismissed: user dismisses
active --> active: re-detected (dedup)
active --> diagnosed: clustered into a diagnosis
active --> expired: not re-detected
active --> dismissed: user dismisses
diagnosed --> expired: retention elapsed
expired --> [*]
dismissed --> [*]