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 --> [*]