feat: 来源归因规则引擎(渠道/AI/搜索词/诚实状态/历史重算)
- constants 规则库 v1:AI/引擎/社交域名表、搜索词参数白名单、付费点击参数、 应用内 UA 标记、CHANNELS 枚举;page_view 白名单开 nav_type/prerendering - services/attribution.classify 纯函数:付费>AI>引擎>社交>referral 分层, UTM 证据叠加(combined/conflict/label_only),应用内 UA 叠加/兜底, 引擎 TLD 国家 variant,搜索词白名单提取(Google 恒空不虚构) - SourceClassification 派生表(迁移 0004):first_touch/session_entry 双 scope, rule_version 可追溯 - ingest 增量 best-effort:首访客/新会话时分类落库(savepoint+静默, 失败不影响采集);validation 对 page_view referrer 完整 URL 参数清洗+截500 - recompute_attribution 命令:全量/按站幂等重算 - API:访客列表归因五字段+channel 筛选、详情 attribution 块(含最近5会话入口)、 dashboard channels 聚合(sources 原口径保留);TS VisitorListParams 加 channel - 测试 97 → 124(引擎20 + 集成/接口7) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,21 @@ def test_sanitize_url_drops_sensitive_params():
|
||||
assert "email=" not in u and "token=" not in u and "utm_source=google" in u
|
||||
assert "monkey=1" in u # fullmatch:含 key 子串的正常参数不误伤
|
||||
|
||||
|
||||
def test_pageview_referrer_url_sanitized():
|
||||
"""page_view 的 properties.referrer 是完整 URL:敏感参数整键剔除后写回。"""
|
||||
ev = _ev(properties={"referrer": "https://www.bing.com/search?q=x&email=a@b.com&token=t"})
|
||||
assert validate_event(ev) is None
|
||||
assert ev["properties"]["referrer"] == "https://www.bing.com/search?q=x"
|
||||
|
||||
|
||||
def test_pageview_referrer_truncated_after_reencode():
|
||||
"""清洗重编码(中文 → %XX 九倍膨胀)可能超出原长:出门统一截 MAX_STR_LEN=500。"""
|
||||
ev = _ev(properties={"referrer": "https://www.bing.com/search?q=" + "词" * 200})
|
||||
assert validate_event(ev) is None # 原文 227 字符过长度门
|
||||
ref = ev["properties"]["referrer"]
|
||||
assert len(ref) == 500 and ref.startswith("https://www.bing.com/search?q=%E8%AF%8D")
|
||||
|
||||
def test_nested_sensitive_key_rejected():
|
||||
assert validate_event(_ev(properties={"utm": {"utm_a": 1, "user_password": "x"}})) == "sensitive_field" # utm 在白名单内,嵌套敏感键仍须命中
|
||||
|
||||
|
||||
Reference in New Issue
Block a user