"""客户生命周期判定纯函数测试(批次A Task4)。 口径(v2 §1.1 #3 + v1 §21 默认,已用户确认):新客 7 天、沉睡 30 天、 历史≥5 条才算沉睡(对齐 churn real min_msgs=5)。analytics 现有页 (churn/客户资产)暂不切换(口径差异 v2 §5 标注),不动 636 既有测试。 """ from app.analytics.lifecycle import DORMANT_DAYS, MIN_HISTORY_MSGS, NEW_DAYS, classify, day_add def test_constants_locked_to_confirmed_defaults(): assert NEW_DAYS == 7 and DORMANT_DAYS == 30 and MIN_HISTORY_MSGS == 5 def test_new_customer(): # 首次沟通在 7 天窗口内 assert ( classify(first_day=20260901, last_day=20260903, prev_day=None, as_of=20260905, hist_msgs=2) == "new" ) # 窗口边界:as_of-6=20260830 含当天共 7 天 → new;再早一天 → 非 new assert classify(20260830, 20260830, None, 20260905, 100) == "new" assert classify(20260829, 20260829, None, 20260905, 100) == "cooling" def test_reactivated_requires_gap_over_30d(): # 当日回流且前次间隔>30 天 assert ( classify( first_day=20260101, last_day=20260905, prev_day=20260801, as_of=20260905, hist_msgs=50 ) == "reactivated" ) # 间隔仅 9 天 → 只是 active assert ( classify( first_day=20260101, last_day=20260905, prev_day=20260827, as_of=20260905, hist_msgs=50 ) == "active" ) # 间隔恰好 30 天 → 严格 >30 不算回流,落回 active assert ( classify( first_day=20260101, last_day=20260905, prev_day=20260806, as_of=20260905, hist_msgs=50 ) == "active" ) # 回流必须当日互动:前次间隔 31 天(>30)但 last_day=as_of-1 → 不算回流,按 gap=1 落 active assert classify(20260101, 20260904, 20260804, 20260905, 50) == "active" def test_active_cooling_dormant_boundaries(): f, m = 20260101, 100 assert classify(f, 20260830, None, 20260905, m) == "active" # 6 天 assert classify(f, 20260829, None, 20260905, m) == "cooling" # 7 天 assert classify(f, 20260807, None, 20260905, m) == "cooling" # 29 天 assert classify(f, 20260806, None, 20260905, m) == "dormant" # 30 天 def test_dormant_requires_history(): # ≥30 天无互动但历史<5 条:不计入任何状态(None) assert classify(20260101, 20260806, None, 20260905, 4) is None assert classify(20260101, 20260806, None, 20260905, 5) == "dormant" def test_no_interaction_returns_none(): assert classify(None, None, None, 20260905, 0) is None def test_day_add(): assert day_add(20260831, 1) == 20260901 assert day_add(20260901, -7) == 20260825