From 3d6064dc143629df2aa7d016459d160d5dba89cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Mon, 12 Oct 2026 23:44:02 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E4=B8=8A=E6=B8=B8=E5=90=B8=E6=94=B6?= =?UTF-8?q?=E5=AE=A1=E6=9F=A5=E4=BF=AE=E8=A1=A5=EF=BC=88=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E7=BA=A0=E5=81=8F/=E4=B8=8A=E6=B8=B8=E6=A0=87=E7=82=B9?= =?UTF-8?q?=E6=81=A2=E5=A4=8D/=E4=BA=A4=E5=8F=89=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E9=97=AD=E5=90=88=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - test_lead_push_cc: 两处"双钉"注释与模块头改为如实的跨文件互补分工 (常量同源钉本文件,字节级措辞钉 test_lead_push_service.py / test_email_rendering.py) - chat_rest: _server_ip/_merge_client_info docstring 与调用点注释恢复 上游半角标点原文(逐字同步,便于将来 diff 式跟上游) - chat.py WS 自报注释补 REST 侧交叉引用,闭合悬空不对称说明 全量回归 459 passed(不变) Co-Authored-By: Claude Code --- app/engine/routes/chat.py | 4 +++- app/engine/routes/chat_rest.py | 12 ++++++------ tests/test_lead_push_cc.py | 9 ++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/engine/routes/chat.py b/app/engine/routes/chat.py index bf3acb5..272bb99 100644 --- a/app/engine/routes/chat.py +++ b/app/engine/routes/chat.py @@ -80,7 +80,9 @@ async def ws_chat(websocket: WebSocket): ) merged_info = {**client_info, **(init_msg.get("client_info") or {})} # 服务端 XFF 优先于客户端自报 ip(客户端自报可伪造,可伪造面最小); - # 无 XFF 时保留客户端自报,user_agent 等其他字段不受影响 + # 无 XFF 时保留客户端自报,user_agent 等其他字段不受影响。 + # (REST 侧已同步上游用直连 host,WS 保持自报——见 + # tests/test_chat_rest_ip.py) if forwarded: merged_info["ip"] = forwarded # Task 10 复审: 专用 site 字段同样赢过 init_msg.client_info diff --git a/app/engine/routes/chat_rest.py b/app/engine/routes/chat_rest.py index 96fcb04..c976efd 100644 --- a/app/engine/routes/chat_rest.py +++ b/app/engine/routes/chat_rest.py @@ -34,16 +34,16 @@ class SessionRequest(BaseModel): def _server_ip(request: Request) -> str: - """服务端可信 IP:XFF 第一段优先,否则直连 host;全空返回空串。 + """服务端可信 IP:XFF 第一段优先,否则直连 host;全空返回空串。 - 同步自上游 ai-kefu(app/api/routes/chat_rest.py):REST 路径原先只在有 - XFF 时覆盖自报 ip,直连(无代理)场景自报假 IP 原样落库。""" + 同步自上游 ai-kefu(app/api/routes/chat_rest.py):REST 路径原先只在有 + XFF 时覆盖自报 ip,直连(无代理)场景自报假 IP 原样落库。""" xff = request.headers.get("x-forwarded-for", "").split(",")[0].strip() return xff or (request.client.host if request.client else "") def _merge_client_info(client_info: dict | None, server_ip: str) -> dict: - """服务端 IP 覆盖自报 ip 键;服务端为空时保留自报(空串不得冲掉客户端值)。""" + """服务端 IP 覆盖自报 ip 键;服务端为空时保留自报(空串不得冲掉客户端值)。""" merged = dict(client_info or {}) if server_ip: merged["ip"] = server_ip @@ -58,8 +58,8 @@ async def chat_session(req: SessionRequest, request: Request): `raw_info` (only when non-None). `client_info` is stored for analytics only (ip/ua/device-id/lang) and never fed to the AI prompt. """ - # 服务端可信 IP 同步自上游 ai-kefu:XFF 第一段优先,无 XFF 用直连 host - # 覆盖客户端自报(可伪造面最小);全空保留自报。?site= 处理不变。 + # 服务端可信 IP 同步自上游 ai-kefu:XFF 第一段优先,无 XFF 用直连 host + # 覆盖客户端自报(可伪造面最小);全空保留自报。?site= 处理不变。 client_info = _merge_client_info(req.client_info, _server_ip(request)) # Task 10: ?site= 记入 client_info 作会话站点标(与 WS init 的 diff --git a/tests/test_lead_push_cc.py b/tests/test_lead_push_cc.py index f92673f..16f9467 100644 --- a/tests/test_lead_push_cc.py +++ b/tests/test_lead_push_cc.py @@ -6,7 +6,8 @@ monkeypatch settings.PUSH_ENABLED → dispatch_lead_push → 查 request_payload 断言按 jc(Task 6)主线重锚,语义等价: - 派生键名: 上游 "区号未确认" → jc "号码补全说明"(号码补全的推送披露口); - 条目措辞: 上游 "渠道(标注)" → jc completion_note 的 "原文→e164+标注" - (标注常量与 cc_completion 同源,双钉防漂移); + (标注常量与 cc_completion 同源;字节级措辞钉在 test_lead_push_service.py / + test_email_rendering.py,跨文件互补); - NOTE_CUSTOMER 已在 jc 并入 NOTE_UNCONFIRMED(customer_stated 未确认与 IP 推测同口径标注,上游的措辞区分被主线统一); - confirmed 入参传裸号原文(jc 生产契约: dispatch 收 normalize_contacts @@ -73,7 +74,8 @@ def test_push_payload_uses_e164_and_filters_underscore(async_db, monkeypatch): p = log.request_payload assert p["contact"]["whatsapp"] == "+254712345678" # 契约值=e164(Task6投影) assert not [k for k in p["profile"] if str(k).startswith("_")] # _cc/_secret不外泄 - # 双钉: 与常量同源 + 字节级措辞(改常量必须联动,措辞本身不得漂移) + # 常量同源钉在本文件,字节级措辞钉在 test_lead_push_service.py / + # test_email_rendering.py(跨文件互补) assert p["profile"]["号码补全说明"] == f"0712345678→+254712345678{NOTE_UNCONFIRMED}" @@ -118,7 +120,8 @@ def test_push_payload_customer_stated_note(async_db, monkeypatch): e164="+256712345678")}}) log = _dispatch(async_db, {"whatsapp": "0712345678"}) p = log.request_payload - # 双钉: 与常量同源 + 字节级措辞(改常量必须联动,措辞本身不得漂移) + # 常量同源钉在本文件,字节级措辞钉在 test_lead_push_service.py / + # test_email_rendering.py(跨文件互补) assert p["profile"]["号码补全说明"] == f"0712345678→+256712345678{NOTE_UNCONFIRMED}" assert p["contact"]["whatsapp"] == "+256712345678"