6.8 KiB
医疗助理“我的客户”数据源只读审计
时间:2026-09-18。审计目录 C:/wechat_rpa 及 C:/Users/isard/AppData/Local/ZhenYangTangRPA 已存在的解密缓存。已通过现有 active_context → discover → NativeClient(write=False) 只读核验当前企微账号;未发送消息、未重新解密、未打开原企微数据库、未修改产品文件。报告只含 schema 和聚合计数,不含客户姓名、手机号、客户 ID 或消息正文。
明确问题
当前医疗助理选择列表不是“企微通讯录→我的客户”:
review_assistant_contacts.py:224只从历史message_table选M:%会话。- 第 196 行虽然读取
external_user_relation_v3,但只用于补充名字,不据此限定客户归属。 - 第 260 行追加所有
wechat_contactV1微信通讯录条目,与企微客户关系没有必然对应。 - 第 21、305 行只允许 M:;当前缓存的两条企微关系联系人均为 S:,被整个漏掉。
review_assistant.py:95同样只接受 M: 医疗助理接收人配置。仅修改列表,S: 选择仍无法启用,需同步调整校验与相应用例。此处只报告,未修改。
当前账号实测
安装版采用当前账号目录内最新的 archive_auto_backup/decrypted user/session/message 缓存,修改时间约 09-18 10:16;源码目录缓存相对更旧,但关键客户关系计数一致。
| 数据 | 安装版最新缓存数量 | 说明 |
|---|---|---|
| user.db / user_table | 172 | 包括当前企业员工,不能整体当客户 |
| user_table 与当前账号同 corp_id | 168 | 是用户缓存,不是“我的客户”成员表 |
| user.db / external_user_ids | 4 | 外部用户集合,含 2 条没有当前账号关系行 |
| user.db / external_user_relation_v3 | 2 | 两条均在 external_user_ids,且能 join user_table |
| user.db / wechat_contactV1 | 214 | 微信通讯录,不应作为我的客户主列表 |
| user.db / wx_friend | 0 | 当前没有显式 UID↔wx_id 映射,不能将214条微信通讯录直接转发送地址 |
| session.db / conversation_table | 96 | S:17,M:1,其余为其他会话类型 |
| message.db / message_table | 699 | 仅统计数量;未查询正文 |
| 关系联系人→已有S会话 | 2 | 两条都包含当前账号及唯一对端,且都有历史消息 |
| 关系联系人→M会话 | 0 | 旧M列表漏掉全部关系联系人 |
两条关系的 status 分别为 2049 和 2057,stranger_type 均为 0,create_time/add_customer_time/remark_time 均大于 0。两条均有 user_table.name 昵称;real_remarks/remarks/corp_remark/recommend_remark 均为空。删除关系表 delete_external_userV1 和黑名单表 blacklist_external_userids 当前均为 0。
哪张表应作为主源
应以**当前已核验账号目录里的 user.db.external_user_relation_v3**作为归属关系的主源,再以 user_id = user_table.id 取名字和身份。该表含 status、stranger_type、add_customer_time、客户来源、客户备注等与本账号关系相关字段;现有归档代码 archive_auto_backup.py:830 也用这张关系表限定 wecom_external_local_uid,不会把全体同事当外部联系人。
external_user_ids、全体 user_table、历史单聊集合、微信通讯录均不能独立证明“是当前账号我的客户”。实测 external_user_ids 比关系表多 2 条,正是不能直接并入的证据。
边界:尚不能仅凭这份缓存证明与企微实时UI完全相同。 客户关系 status 是组合标志,现有代码没有 2049/2057 的定义,实测样本也不足以推导每个位意义。不能猜测 status==1、status!=0 或某个位来断言关系当前仍有效。关系表可以提供明确归属候选,但若要求严格排除已删/待确认关系,需要有经过验证的状态定义或只读UI对照,不能用历史消息或姓名推断。
ID、名称与可发送会话映射
- 使用关系表的数值型
user_id作为本地外部联系人 UID,作用域包含当前账号。它不等同于官方 API 的字符串external_userid,不能互换。user_table有 unionid 字段,但当前表结构没有明确官方 external_userid 字段;本轮没有解码不透明 protobuf 字段。 - 展示名字优先读取
real_remarks → remarks → user_table.name → user_table.real_name;名称只用于展示和搜索,不作为身份、去重或发送地址。当前两条需要回落到昵称。 - 从已经存在的 session/message 会话里匹配 S::格式
S:<uid1>_<uid2>,必须恰有一端等于当前账号、另一端等于关系 UID。当前两条均通过该映射,未发现歧义。保留数据库里的原始会话 ID,不自行猜拼接或依赖名字。 - M: 只有在对端 UID 与关系 UID 有明确对应时才可候选;当前样本为 0。
wechat_contactV1.gene不能猜作 UID;wx_friend当前为空,不具备214条微信通讯录到会话的可靠映射。 - 客户归属与可发送性应分开:有关系但没有可核验会话的客户仍可展示为暂不可选,不应要求先出现消息才能成为“我的客户”;已映射会话也不能据此保证对端现在接受消息,发送前仍应保留当前账号校验与联系人限制检查。
session.db 还存在 crm_customer_conversation_relation2、inner_customer_conversation_relation、outer_customer_conversation_relationV2,当前均为空,不能作为当前列表来源。user_extend.db 仅同事备注、休假相关表,没有更完整的我的客户表。
联系人限制记录
源码目录 contactBlocked 为 0,unrepliable_sessions 为 0。安装版 contactBlocked 有 1 条,可在内存中按账号+会话哈希匹配到一个 S: 关系联系人,关系 status=2049,但记录已超过现有 6 小时有效期。该记录是曾经不能回复的证据,不能用来定义 status=2049 的含义,也不能作为永久删除关系的依据。
现有 contact_reply_guard.py 根据系统验证提示/明确传输拒绝识别限制,protocol_engine.py:354 维护短期屏蔽;这些记录是发送保护,不是我的客户名单。医疗助理列表应共享保护结果,不能用屏蔽名单反推出全部客户。
交付与限制
schema-aggregates.json:源码缓存各表 schema 与数量。relation-aggregates.json:源码当前账号关系状态、名称覆盖、S/M映射数量。packaged-aggregates.json:安装版最新缓存、关系及联系人保护计数。- 三个
audit_*.py为本次只读审计脚本,只读已解密缓存,输出聚合结果。
当前缓存已经具备“按本账号关系列出候选 + 显示昵称/备注 + 核验既有S会话”的关键数据;不需要为此读取消息正文或强制解密。严格实时UI成员一致性及 status 位定义仍缺证据,本审计未声称解决这些未验证问题。