File size: 5,357 Bytes
a1757c5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""
Unit tests for compose() — the brain.

Tests cover: message body generation, CTA, template params,
category-specific outputs, and customer-facing messages.
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from app.core.compose import compose


# ── Sample contexts for testing ─────────────────────────────────────────────

DENTIST_CATEGORY = {
    "slug": "dentists",
    "voice": {"tone": "peer_clinical", "vocab_taboo": ["cure", "guaranteed"]},
    "peer_stats": {"avg_rating": 4.4, "avg_ctr": 0.030},
    "digest": [
        {"id": "d_2026W17_jida_fluoride", "kind": "research",
         "title": "3-mo fluoride recall cuts caries recurrence 38% better than 6-mo",
         "source": "JIDA Oct 2026, p.14", "trial_n": 2100,
         "patient_segment": "high_risk_adults"}
    ],
    "offer_catalog": [],
    "seasonal_beats": [],
    "trend_signals": [],
}

MERCHANT_DRMEERA = {
    "merchant_id": "m_001_drmeera",
    "category_slug": "dentists",
    "identity": {"name": "Dr. Meera's Dental Clinic", "owner_first_name": "Meera",
                 "city": "Delhi", "locality": "Lajpat Nagar", "verified": True,
                 "languages": ["en", "hi"]},
    "subscription": {"status": "active", "plan": "Pro", "days_remaining": 82},
    "performance": {"views": 2410, "calls": 18, "directions": 45, "ctr": 0.021,
                    "delta_7d": {"views_pct": 0.18, "calls_pct": -0.05}},
    "offers": [{"id": "o1", "title": "Dental Cleaning @ ₹299", "status": "active"}],
    "customer_aggregate": {"total_unique_ytd": 540, "lapsed_180d_plus": 78,
                           "retention_6mo_pct": 0.38, "high_risk_adult_count": 124},
    "signals": ["stale_posts:22d", "ctr_below_peer_median"],
    "review_themes": [],
}

TRIGGER_RESEARCH = {
    "id": "trg_001", "scope": "merchant", "kind": "research_digest",
    "source": "external", "merchant_id": "m_001_drmeera",
    "payload": {"category": "dentists", "top_item_id": "d_2026W17_jida_fluoride"},
    "urgency": 2, "suppression_key": "research:dentists:2026-W17",
    "expires_at": "2026-05-03T00:00:00Z",
}

TRIGGER_PERF_DIP = {
    "id": "trg_004", "scope": "merchant", "kind": "perf_dip",
    "source": "internal", "merchant_id": "m_002",
    "payload": {"metric": "calls", "delta_pct": -0.50, "window": "7d"},
    "urgency": 4, "suppression_key": "perf_dip:m_002:calls:2026-W17",
}

CUSTOMER_PRIYA = {
    "customer_id": "c_001_priya",
    "merchant_id": "m_001_drmeera",
    "identity": {"name": "Priya", "language_pref": "hi-en mix"},
    "relationship": {"visits_total": 4, "last_visit": "2026-05-12"},
    "state": "lapsed_soft",
}

TRIGGER_RECALL = {
    "id": "trg_003", "scope": "customer", "kind": "recall_due",
    "source": "internal", "merchant_id": "m_001_drmeera",
    "customer_id": "c_001_priya",
    "payload": {"service_due": "6_month_cleaning",
                "available_slots": [{"label": "Wed 5 Nov, 6pm"}, {"label": "Thu 6 Nov, 5pm"}]},
    "urgency": 3, "suppression_key": "recall:c_001:6mo",
}


# ── Tests ────────────────────────────────────────────────────────────────────

def test_research_digest_compose():
    result = compose(DENTIST_CATEGORY, MERCHANT_DRMEERA, TRIGGER_RESEARCH)
    assert "body" in result
    assert len(result["body"]) > 30
    # Should mention JIDA
    assert "JIDA" in result["body"] or "jida" in result["body"].lower()
    # Should mention the merchant's patients
    assert "124" in result["body"] or "high-risk" in result["body"]
    # Should have a CTA
    assert "?" in result["body"]
    print(f"PASS: research_digest — {result['body'][:80]}...")


def test_perf_dip_compose():
    merchant = {**MERCHANT_DRMEERA, "merchant_id": "m_002",
                "performance": {"views": 980, "calls": 4, "delta_7d": {"calls_pct": -0.50}}}
    result = compose(DENTIST_CATEGORY, merchant, TRIGGER_PERF_DIP)
    assert "body" in result
    assert "50%" in result["body"] or "calls" in result["body"]
    print(f"PASS: perf_dip — {result['body'][:80]}...")


def test_recall_customer_facing():
    result = compose(DENTIST_CATEGORY, MERCHANT_DRMEERA, TRIGGER_RECALL, CUSTOMER_PRIYA)
    assert "body" in result
    assert "Priya" in result["body"]
    assert "Dental Clinic" in result["body"] or "Dr. Meera" in result["body"]
    print(f"PASS: recall — {result['body'][:80]}...")


def test_no_taboo_terms():
    result = compose(DENTIST_CATEGORY, MERCHANT_DRMEERA, TRIGGER_RESEARCH)
    body_l = result["body"].lower()
    assert "cure" not in body_l
    assert "guaranteed" not in body_l
    print("PASS: no taboo terms in dentist output")


def test_compose_returns_required_keys():
    result = compose(DENTIST_CATEGORY, MERCHANT_DRMEERA, TRIGGER_RESEARCH)
    for key in ("body", "cta", "rationale"):
        assert key in result, f"Missing key: {key}"
    print("PASS: all required keys present")


if __name__ == "__main__":
    test_research_digest_compose()
    test_perf_dip_compose()
    test_recall_customer_facing()
    test_no_taboo_terms()
    test_compose_returns_required_keys()
    print("\nAll compose tests passed!")