issue #125: 情感态收尾——per-user慢层私聊作用域修正 + 反应式路径自我披露渲染 #130

Merged
Yushu merged 2 commits from feat/125-affective-state-closure into main 2026-08-14 01:00:08 +00:00
Member

Closes #125

实现

一、delta.py::_apply_interaction_polarity 私聊场景读写错作用域修正

  • 私聊 chat_id({room_id}.p)此前无条件读写 "group" 作用域,与 ADR-0005"私聊快层退向 per-user 慢情感态"的拍板决策相悖。改为按 is_private_chat_id(chat_id) 分流:私聊读 ("user", chat_id.removesuffix(".p")) 作衰减目标,群聊分支代码路径零改动。
  • 对方 id 用 chat_id.removesuffix(".p") 机械换算,不采用 issue #125 AC 字面建议的"从 speaker_polarity/delta entries 取对方 id"——这是对 AC 措辞的有意偏离(同 issue #94 先例做法),理由:speaker_polarity 完全依赖 LLM 抽取回填,delta.py 对它没有任何校验;机械换算复用 reflection.py::_apply_outcome/runtime_loop.py 已有先例,不依赖模型输出准确性。已在 ADR-0005 更新节记录。
  • 私聊场景下 per-group"跟随更新"整段跳过,不写 group 也不改道写 user——两轴对抗校验(设计阶段,三路独立复核)确认"改道写 user 作用域顺手给 energy/dominance 一个产出方"这条方案会复活 ADR-0005"拒绝了"节明文否决过的方案本身(per-user 慢情感态低通滤波房间级快情感态),且 reflection.py::_apply_outcome(全仓唯一纯私聊路径)面对相同处境时选的正是 per-user 自己的累积函数,不是复用 per-group 的追逐函数。
  • per-user 慢层 energy 轴本票维持零产出方——这是 AC 给出的两个合法选项之一("显式记为维持只写 valence"),已在 ADR-0005 更新节记录理由,不是遗漏。

二、反应式路径补自我披露渲染

  • _full_frozen_snapshotrun()/run_callback() 共用)与 _run_event_driven_turnrun_environment_signal()/群聊即刻追问共用)各补一次 render_affective_state_fact,直接复用 Drive Tick 已用的同一份渲染函数,不另写。四个公开入口经这两条共用管线自动全部覆盖。
  • 只读一次快情感态,往下传给 _recall_events/_scored_events 复用(新增 affective_state 覆盖参数,同 entry_reactive.py::_debounced_flush 既有"读过就复用"先例)——mood_congruence 命中时不再多打一次存储读,get_fast_affective_state 每轮调用次数固定为 1。

两轴 review 发现与修正(2 项,全部确认,均为文档准确性问题)

  1. [MEDIUM standards] _full_frozen_snapshot/_run_event_driven_turn 的文档字符串把自我披露列为拼装顺序里的第二段,但实际 return 元组里排在关系网之后、是第四段——两处对称地写错。已改为与实际拼装顺序一致。
  2. [LOW standards] _effective_fast_state 的文档字符串仍称"本类内两处消费方(打字节奏、mood_congruence)",未把本票新增的自我披露消费方计入。已改为"三处消费方"。

文档

  • docs/adr/0005-affective-state.md 新增更新节,记录私聊作用域修正的诊断与决策(含被否决的"跟随更新改道"方案、E 点对 AC 字面建议的偏离理由、energy 轴维持零产出方的理由)与反应式自我披露渲染的接线方式。
  • docs 分支按规矩不推送,仅本地提交。

测试

  • Part 1 新增 5 个测试(TestPrivateChatDecaysTowardPerUserSlowState):私聊退 per-user、群聊对照组不变、私聊不写 group、对方 id 机械换算不依赖 speaker_polarity、per-user 极端值不泄漏进群聊(A 型陷阱钉住)。
  • Part 2 新增 3 个测试(TestSelfDisclosureSnapshot)+ 1 个复用验证测试,另修复 5 个因自我披露改为无条件渲染而失真的既有测试("零读取"断言改为"读取计数为 1","内容为空"断言改为"只剩自我披露")。
  • 变异测试验证全部 6 处新增守卫可被单独抓住(私聊读侧分流、私聊跳过跟随更新、自我披露读+渲染共两处组装点、mood_congruence 复用覆盖参数)。
  • 全量测试 1746 passed;ruff 全绿;ty check 对本片改动文件全绿。

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

Closes #125 ## 实现 **一、`delta.py::_apply_interaction_polarity` 私聊场景读写错作用域修正** - 私聊 chat_id(`{room_id}.p`)此前无条件读写 `"group"` 作用域,与 ADR-0005"私聊快层退向 per-user 慢情感态"的拍板决策相悖。改为按 `is_private_chat_id(chat_id)` 分流:私聊读 `("user", chat_id.removesuffix(".p"))` 作衰减目标,群聊分支代码路径零改动。 - 对方 id 用 `chat_id.removesuffix(".p")` 机械换算,不采用 issue #125 AC 字面建议的"从 speaker_polarity/delta entries 取对方 id"——这是对 AC 措辞的有意偏离(同 issue #94 先例做法),理由:`speaker_polarity` 完全依赖 LLM 抽取回填,delta.py 对它没有任何校验;机械换算复用 `reflection.py::_apply_outcome`/`runtime_loop.py` 已有先例,不依赖模型输出准确性。已在 ADR-0005 更新节记录。 - 私聊场景下 per-group"跟随更新"整段跳过,不写 group 也不改道写 user——两轴对抗校验(设计阶段,三路独立复核)确认"改道写 user 作用域顺手给 energy/dominance 一个产出方"这条方案会复活 ADR-0005"拒绝了"节明文否决过的方案本身(per-user 慢情感态低通滤波房间级快情感态),且 `reflection.py::_apply_outcome`(全仓唯一纯私聊路径)面对相同处境时选的正是 per-user 自己的累积函数,不是复用 per-group 的追逐函数。 - per-user 慢层 energy 轴本票维持零产出方——这是 AC 给出的两个合法选项之一("显式记为维持只写 valence"),已在 ADR-0005 更新节记录理由,不是遗漏。 **二、反应式路径补自我披露渲染** - `_full_frozen_snapshot`(`run()`/`run_callback()` 共用)与 `_run_event_driven_turn`(`run_environment_signal()`/群聊即刻追问共用)各补一次 `render_affective_state_fact`,直接复用 Drive Tick 已用的同一份渲染函数,不另写。四个公开入口经这两条共用管线自动全部覆盖。 - 只读一次快情感态,往下传给 `_recall_events`/`_scored_events` 复用(新增 `affective_state` 覆盖参数,同 `entry_reactive.py::_debounced_flush` 既有"读过就复用"先例)——mood_congruence 命中时不再多打一次存储读,`get_fast_affective_state` 每轮调用次数固定为 1。 ## 两轴 review 发现与修正(2 项,全部确认,均为文档准确性问题) 1. **[MEDIUM standards]** `_full_frozen_snapshot`/`_run_event_driven_turn` 的文档字符串把自我披露列为拼装顺序里的第二段,但实际 return 元组里排在关系网之后、是第四段——两处对称地写错。已改为与实际拼装顺序一致。 2. **[LOW standards]** `_effective_fast_state` 的文档字符串仍称"本类内两处消费方(打字节奏、mood_congruence)",未把本票新增的自我披露消费方计入。已改为"三处消费方"。 ## 文档 - `docs/adr/0005-affective-state.md` 新增更新节,记录私聊作用域修正的诊断与决策(含被否决的"跟随更新改道"方案、E 点对 AC 字面建议的偏离理由、energy 轴维持零产出方的理由)与反应式自我披露渲染的接线方式。 - `docs` 分支按规矩不推送,仅本地提交。 ## 测试 - Part 1 新增 5 个测试(`TestPrivateChatDecaysTowardPerUserSlowState`):私聊退 per-user、群聊对照组不变、私聊不写 group、对方 id 机械换算不依赖 speaker_polarity、per-user 极端值不泄漏进群聊(A 型陷阱钉住)。 - Part 2 新增 3 个测试(`TestSelfDisclosureSnapshot`)+ 1 个复用验证测试,另修复 5 个因自我披露改为无条件渲染而失真的既有测试("零读取"断言改为"读取计数为 1","内容为空"断言改为"只剩自我披露")。 - 变异测试验证全部 6 处新增守卫可被单独抓住(私聊读侧分流、私聊跳过跟随更新、自我披露读+渲染共两处组装点、mood_congruence 复用覆盖参数)。 - 全量测试 1746 passed;ruff 全绿;`ty check` 对本片改动文件全绿。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
一、delta.py::_apply_interaction_polarity 私聊场景读写错作用域修正:
- 按 is_private_chat_id 分流,私聊快层衰减目标改读 ("user", 对方id)(对方id
  用 chat_id.removesuffix(".p") 机械换算,不依赖 LLM 回填的 speaker_polarity)
- 私聊场景下 per-group"跟随更新"整段跳过(两轴对抗校验确认改道写 user 作用域
  会复活 ADR-0005 明文否决过的方案),群聊分支代码路径零改动
- per-user 慢层 energy 轴本票维持零产出方(AC 给出的合法选项,非缩水)

二、反应式路径补自我披露渲染(run/run_callback/run_environment_signal/
run_immediate_followup 四条入口,经两条共用组装管线各补一次):
- 复用既有 render_affective_state_fact,不另写
- 读一次快情感态,往下传给 _recall_events/_scored_events 复用,
  mood_congruence 命中时不再多打一次存储读

变异测试验证 6 处新增守卫全部可被单独抓住;ADR-0005 更新节已补(docs 分支,
本地提交不推送)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
两轴 review 发现 2 项,均确认,均为文档准确性问题(无功能改动):

1. [MEDIUM standards] _full_frozen_snapshot/_run_event_driven_turn 的文档
   字符串把自我披露列为第二段(画像之后),但实际 return 元组里排在关系网
   之后、是第四段——两处对称地写错了同一件事。改成与实际拼装顺序一致。

2. [LOW standards] _effective_fast_state 的文档字符串仍称"本类内两处消费方
   (打字节奏、mood_congruence)",未把本票新增的自我披露消费方计入,改为
   "三处消费方"。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Yushu merged commit fc917417ce into main 2026-08-14 01:00:08 +00:00
Yushu deleted branch feat/125-affective-state-closure 2026-08-14 01:00:09 +00:00
Sign in to join this conversation.
No description provided.