fix: 环境遥测拆独立类型 AmbientTelemetrySignal——堵住 chat_id 误标泄漏 (issue #153) #162

Merged
Yushu merged 1 commit from feat/153-ambient-telemetry-signal into main 2026-08-18 08:55:02 +00:00
Member

Closes #153

修复内容

按 ADR-0014(issue #108 grill Q3 更新节)修复一处真实隐私泄漏:环境遥测(per-user,如私人摄像头/设备感知流)此前复用 per-chat_id 的 EnvironmentSignalchat_id 由 host "挑一个会话当呈现载体"、代码不做任何校验——填成群聊时,基于私人遥测生成的回复会真实发进那个群、全体成员可见。

  • environmental_awareness.py:新增 AmbientTelemetrySignal(user_id, content, plugin_name)不带 chat_id 字段——从类型层面排除误标进群聊的可能,不是加一道校验。新增 to_ambient_telemetry_signal(signal) 转换函数:从已识别为遥测的 EnvironmentSignal.subject_id 派生 user_id("真 user_id",遥测场景下事实上必填),chat_id 从此完全不读取;subject_id 缺失时 fail-closed 丢弃,不猜测、不回退。is_ambient_telemetry/白名单识别机制字节级不变。新增 tier2_significance_score_for_telemetry(遥测内容恒 notable)与改写后接受新类型的 render_ambient_telemetry_directiveEnvironmentSignal 类文档本就是"原义"未被污染,模块级文档字符串重写为指向新类型。
  • environment_pipeline.py_process_environment_signal 里遥测识别提到任何 chat_id 绑定/使用之前(包括死循环熔断计数——这一步在旧代码里比遥测判定更早,若不提前,即便最终发送目标是对的,熔断计数状态也会被 host 提供的 chat_id 污染)。识别出遥测后整体转交新函数 _process_ambient_telemetry_signal,全程只用 f"{user_id}.p"
  • runtime_loop.pyrun_environment_signal 去掉 ambient 参数(遥测不再经过这里);新增 run_ambient_telemetry_signal,目标 chat_id 同样只从 user_id 推导。

设计判断(已过对抗式验证)

"host 怎么把 user_id/content 交给 core 而不经 chat_id"这一步 ADR 原文没有讲到代码层面——两轮独立评审核实后确认:host 仍只实现同一个 to_environment_signal Protocol 方法(不新增 port,匹配 AC"不新增 host 侧映射机制"+"识别机制不变"两条约束),subject_id 是唯一可用的真实 user_id 来源,chat_id 转换后完全弃用。

两轴 review 额外修复

  • run_ambient_telemetry_signalquery_text 最初遗漏 plugin_name,会让 host 配置的以插件名(如 "camera")为 trigger_keyword 的 Knowledge/Lore 静默失效——已修复并补变异测试验证过的回归测试。
  • AC5 回归测试最初用了数字相同的 chat_id/user_id("1.g"/"1"),测不出"从 chat_id 做字符串变换派生目标"这类看似正确实则读了 chat_id 的回归——已改成不撞号的数值("999.g"/"1")。
  • gate_pipeline.py/_process_ambient_telemetry_signal 两处过期/缺失的说明性注释。

测试

  • 回归测试直接命中 AC5 字面要求:构造一个数值不同的群聊 chat_id 作为输入,断言最终 send_private_msg 目标是 f"{user_id}.p",且群聊自身的情感态/死循环熔断状态全程未被触碰。
  • subject_id 缺失时 fail-closed 丢弃的单测+e2e 测试。
  • run_ambient_telemetry_signal 的 Knowledge 触发注入回归测试。
  • 全部 1908 个测试通过;对 3 处安全关键路径(识别顺序、chat_id 推导、fail-closed 判空)+ 1 处 review 修复点做过变异测试,确认新增测试真实覆盖(其中一次变异测试当场发现了一个真实的测试覆盖缺口——死循环熔断计数未被任何测试断言,已补上)。
  • ruff checklint-importsuvx ty check 均通过。
Closes #153 ## 修复内容 按 ADR-0014(issue #108 grill Q3 更新节)修复一处真实隐私泄漏:环境遥测(per-user,如私人摄像头/设备感知流)此前复用 per-chat_id 的 `EnvironmentSignal`,`chat_id` 由 host "挑一个会话当呈现载体"、代码不做任何校验——填成群聊时,基于私人遥测生成的回复会真实发进那个群、全体成员可见。 - **`environmental_awareness.py`**:新增 `AmbientTelemetrySignal(user_id, content, plugin_name)`,**不带 `chat_id` 字段**——从类型层面排除误标进群聊的可能,不是加一道校验。新增 `to_ambient_telemetry_signal(signal)` 转换函数:从已识别为遥测的 `EnvironmentSignal.subject_id` 派生 `user_id`("真 user_id",遥测场景下事实上必填),`chat_id` 从此完全不读取;`subject_id` 缺失时 fail-closed 丢弃,不猜测、不回退。`is_ambient_telemetry`/白名单识别机制字节级不变。新增 `tier2_significance_score_for_telemetry`(遥测内容恒 notable)与改写后接受新类型的 `render_ambient_telemetry_directive`。`EnvironmentSignal` 类文档本就是"原义"未被污染,模块级文档字符串重写为指向新类型。 - **`environment_pipeline.py`**:`_process_environment_signal` 里遥测识别提到**任何 chat_id 绑定/使用之前**(包括死循环熔断计数——这一步在旧代码里比遥测判定更早,若不提前,即便最终发送目标是对的,熔断计数状态也会被 host 提供的 chat_id 污染)。识别出遥测后整体转交新函数 `_process_ambient_telemetry_signal`,全程只用 `f"{user_id}.p"`。 - **`runtime_loop.py`**:`run_environment_signal` 去掉 `ambient` 参数(遥测不再经过这里);新增 `run_ambient_telemetry_signal`,目标 chat_id 同样只从 `user_id` 推导。 ## 设计判断(已过对抗式验证) "host 怎么把 user_id/content 交给 core 而不经 chat_id"这一步 ADR 原文没有讲到代码层面——两轮独立评审核实后确认:host 仍只实现同一个 `to_environment_signal` Protocol 方法(不新增 port,匹配 AC"不新增 host 侧映射机制"+"识别机制不变"两条约束),`subject_id` 是唯一可用的真实 user_id 来源,`chat_id` 转换后完全弃用。 ## 两轴 review 额外修复 - `run_ambient_telemetry_signal` 的 `query_text` 最初遗漏 `plugin_name`,会让 host 配置的以插件名(如 "camera")为 trigger_keyword 的 Knowledge/Lore 静默失效——已修复并补变异测试验证过的回归测试。 - AC5 回归测试最初用了数字相同的 chat_id/user_id("1.g"/"1"),测不出"从 chat_id 做字符串变换派生目标"这类看似正确实则读了 chat_id 的回归——已改成不撞号的数值("999.g"/"1")。 - `gate_pipeline.py`/`_process_ambient_telemetry_signal` 两处过期/缺失的说明性注释。 ## 测试 - 回归测试直接命中 AC5 字面要求:构造一个数值不同的群聊 chat_id 作为输入,断言最终 `send_private_msg` 目标是 `f"{user_id}.p"`,且群聊自身的情感态/死循环熔断状态全程未被触碰。 - `subject_id` 缺失时 fail-closed 丢弃的单测+e2e 测试。 - `run_ambient_telemetry_signal` 的 Knowledge 触发注入回归测试。 - 全部 1908 个测试通过;对 3 处安全关键路径(识别顺序、chat_id 推导、fail-closed 判空)+ 1 处 review 修复点做过变异测试,确认新增测试真实覆盖(其中一次变异测试当场发现了一个真实的测试覆盖缺口——死循环熔断计数未被任何测试断言,已补上)。 - `ruff check`、`lint-imports`、`uvx ty check` 均通过。
按 ADR-0014 issue #108 grill Q3 更新节修复真实隐私泄漏:环境遥测(per-user 私人
感知流)此前复用 per-chat_id 的 EnvironmentSignal,host 填的 chat_id 一旦被误标
成群聊,基于私人遥测生成的回复会真实发进那个群。新增不带 chat_id 字段的
AmbientTelemetrySignal,目标 chat_id 全程只能机械推导成 f"{user_id}.p",识别
判定提到任何 chat_id 绑定/使用之前,从类型和执行顺序两个层面排除误标可能。

两轴 review 额外抓到并修复:query_text 遗漏 plugin_name 导致 Knowledge/Lore
按插件名触发失效、回归测试 chat_id/user_id 数字撞号削弱了测试说服力。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Yushu merged commit e3abcbd82d into main 2026-08-18 08:55:02 +00:00
Yushu deleted branch feat/153-ambient-telemetry-signal 2026-08-18 08:55:03 +00:00
Sign in to join this conversation.
No description provided.