Delta 压缩容错 + valence 产出方:情感态 valence 三层至今恒为 0 #94

Closed
opened 2026-07-29 08:23:04 +00:00 by KumaAgent · 0 comments
Member

来源:2026-07-29 全 ADR 查漏。本票是第一批里最重要的一张——它修的是「一个核心子系统至今完全不工作」,不是一个边角 bug。两件事有先后依赖,必须同票

Problem A:Delta 压缩失败 = 该 chat 本批原文永久消失

storage.py::drain_delta 的顺序是 select → delete → commit → return

entries = [_to_delta_entry(row) for row in rows]
await s.execute(delete(DeltaBufferModel).where(...))
await s.commit()
return entries

删除先于 compress 提交。而 delta.py 全文零 try/except(已核实),llm_client.complete 是裸调用(delta.py:193)。LLM 抛异常 → 该 chat 本批对话原文永久消失,不需要 host、不需要真实流量就会发生。

同一个 cycle 里 persona_drift_guard 反而有完整 try/except + fail-closed 测试,说明容错在这条链上做了一半,缺的恰好是有数据丢失后果的那一半。ADR-0009「更新(2026-07-08):压缩容错」明写:

compress() 连续失败时降级为原样转存低置信 tentative + 标记待重试,而非静默丢弃

ADR-0010 的更新节也点过「先删库提交再调 LLM,只靠下游拦会丢数据」。

Problem B:f(互动极性) 从来没有产出方 → valence 三层恒为 0

ADR-0005 与 CONTEXT.md「快情感态」条断言:

valence += f(互动极性) − k_fast·(valence − slow_valence)

实测:valence_raw_delta 这个参数名在整个 src/ 里只出现在 affective_state.py 自己的签名与函数体内:194 :209 :247 :263)。update_fast_state 的两个调用点——__init__.py:2168(只传 energy_raw_delta)与 reflection.py:253(只传 outcome=)——没有任何一个传它,默认值 0.0update_slow_* 同理。

结论:valence 快层/慢层 per-user/慢层 per-group 三层全部恒为 0,永远不会变。

下游三处因此是死码(均已核实):

位置 死法
recall.py:57 if current_mood.valence < 0 mood_congruence 负性护栏从未触发过——issue #67 的 AC 称它「唯一不可省略的行为约束」
reflection.py:94-98 annoyed 判定 比较 valence_at_sendcurrent_valence,两者恒 0、差恒 0,永不超阈值;三态结局分类器实际只跑两态
自我披露的 valence 倾向半边 同上,输入恒 0

更值得警惕的是精化层反而全建好了k_valence_negative 连构造校验都写了、last_stimulus_label 抗刷槽位也在——整个 valence 子系统只缺最底下那块砖

另外 delta.py 落盘事件时读当前快情感态打 mood 标签,valence 恒 0 意味着每条事件的 mood 标签 valence 维都是 0,与当前值比较恒等 → mood_congruence 的 valence 维对排序零贡献(energy 维仍有效,因为环境信号在喂它)。

依赖关系(为什么同票、什么顺序)

valence 产出方要挂在 Delta 压缩那次 LLM 调用上(已拍板,见下)。而那正是 Problem A 里会丢数据的那条路径——先落容错,再挂产出方,否则压缩失败会同时丢原文和情感更新。

决策(已 grill 拍板)

产出方位置 = 蹭 Delta 压缩那次 LLM 调用,作为第四个搭便车字段(已有 sensitive / importance / 回指消解参与者)。

拍板理由:

  • 零额外 LLM 调用,同 importance 打标「搭便车、零额外调用」的既有先例;
  • 不撞红线1(前台短循环至高优先级,禁止往回复路径加 LLM 工作);
  • 「与分钟级快层有张力」这个反对比听起来弱——arise_delta_compression_interval_seconds 默认 300 秒 = 5 分钟,本身就是分钟级;
  • 否决了本地廉价启发式:「互动极性」是语义判断,中文聊天的关键词情感启发式很弱,而 valence 是三处机制的输入源,判错会扩散;
  • 排除了「复用已有 Outcome 分类器当产出方」——reflection._classify 是拿 valence 变化判 annoyed 的,valence 依赖它就成环。正确链条是 产出方 → valence → outcome → dominance,现在断在根上。

Acceptance criteria

  • 先落容错drain_delta 之后、compress 失败时不得丢原文。按 ADR-0009 原文降级为「原样转存低置信 tentative + 标记待重试」,或等价地把原始 delta 重新入库。补一条「LLM 抛异常后原文仍在」的测试。
  • Delta 压缩的抽取 schema 新增互动极性字段,沿用既有 fail-closed 风格(字段缺失/类型非法时取中性值,不猜测)。
  • 接线两个 update_fast_state 调用点传入 valence_raw_delta;慢层 per-user 同步接上。
  • 验收必须包含「annoyed 在端到端里真的出现一次」——否则很容易只把方程接上、三态仍然只跑两态。这条是本票最容易假通过的地方:landed/fell-flat 在 valence 恒 0 时也能出现,光看「测试全绿」区分不出来。
  • 补一条守卫,锁住「valence_raw_delta 至少有一个非零生产调用点」——防止未来重构又把产出方摘掉而无人发现(同本仓「穷举守卫」先例,ADR-0010 issue #83 节背书)。
  • 顺带确认 mood_congruence 的 valence 维在接上产出方后真的开始参与排序(此前恒等于 0 相比,零贡献)。

Not in scope

  • 不做「未获回应升级」那条 valence 输入源(查漏判为留痕,在文档批处理)。
  • 不碰 send 失败兜底(另一张票)。
  • 不做任何结构调整。
> 来源:2026-07-29 全 ADR 查漏。本票是**第一批**里最重要的一张——它修的是「一个核心子系统至今完全不工作」,不是一个边角 bug。两件事**有先后依赖,必须同票**。 ## Problem A:Delta 压缩失败 = 该 chat 本批原文永久消失 `storage.py::drain_delta` 的顺序是 **select → delete → commit → return**: ```python entries = [_to_delta_entry(row) for row in rows] await s.execute(delete(DeltaBufferModel).where(...)) await s.commit() return entries ``` 删除**先于** compress 提交。而 `delta.py` **全文零 `try`/`except`**(已核实),`llm_client.complete` 是裸调用(`delta.py:193`)。**LLM 抛异常 → 该 chat 本批对话原文永久消失**,不需要 host、不需要真实流量就会发生。 同一个 cycle 里 `persona_drift_guard` 反而有完整 try/except + fail-closed 测试,说明容错在这条链上做了一半,缺的恰好是**有数据丢失后果的那一半**。ADR-0009「更新(2026-07-08):压缩容错」明写: > compress() 连续失败时降级为原样转存低置信 tentative + 标记待重试,而非静默丢弃 ADR-0010 的更新节也点过「先删库提交再调 LLM,只靠下游拦会丢数据」。 ## Problem B:`f(互动极性)` 从来没有产出方 → valence 三层恒为 0 ADR-0005 与 CONTEXT.md「快情感态」条断言: > valence += f(互动极性) − k_fast·(valence − slow_valence) **实测:`valence_raw_delta` 这个参数名在整个 `src/` 里只出现在 `affective_state.py` 自己的签名与函数体内**(`:194 :209 :247 :263`)。`update_fast_state` 的两个调用点——`__init__.py:2168`(只传 `energy_raw_delta`)与 `reflection.py:253`(只传 `outcome=`)——**没有任何一个传它**,默认值 `0.0`。`update_slow_*` 同理。 **结论:valence 快层/慢层 per-user/慢层 per-group 三层全部恒为 0,永远不会变。** 下游三处因此是死码(均已核实): | 位置 | 死法 | |---|---| | `recall.py:57` `if current_mood.valence < 0` | mood_congruence **负性护栏从未触发过**——issue #67 的 AC 称它「唯一不可省略的行为约束」 | | `reflection.py:94-98` `annoyed` 判定 | 比较 `valence_at_send` 与 `current_valence`,两者恒 0、差恒 0,**永不超阈值**;三态结局分类器实际只跑两态 | | 自我披露的 valence 倾向半边 | 同上,输入恒 0 | **更值得警惕的是精化层反而全建好了**:`k_valence_negative` 连构造校验都写了、`last_stimulus_label` 抗刷槽位也在——**整个 valence 子系统只缺最底下那块砖**。 另外 `delta.py` 落盘事件时读当前快情感态打 `mood` 标签,valence 恒 0 意味着**每条事件的 mood 标签 valence 维都是 0,与当前值比较恒等** → mood_congruence 的 valence 维对排序**零贡献**(energy 维仍有效,因为环境信号在喂它)。 ## 依赖关系(为什么同票、什么顺序) valence 产出方要挂在 **Delta 压缩那次 LLM 调用**上(已拍板,见下)。而那正是 Problem A 里会丢数据的那条路径——**先落容错,再挂产出方**,否则压缩失败会同时丢原文和情感更新。 ## 决策(已 grill 拍板) **产出方位置 = 蹭 Delta 压缩那次 LLM 调用**,作为第四个搭便车字段(已有 `sensitive` / `importance` / 回指消解参与者)。 拍板理由: - **零额外 LLM 调用**,同 `importance` 打标「搭便车、零额外调用」的既有先例; - **不撞红线1**(前台短循环至高优先级,禁止往回复路径加 LLM 工作); - 「与分钟级快层有张力」这个反对**比听起来弱**——`arise_delta_compression_interval_seconds` **默认 300 秒 = 5 分钟**,本身就是分钟级; - 否决了本地廉价启发式:「互动极性」是语义判断,中文聊天的关键词情感启发式很弱,而 valence 是三处机制的输入源,判错会扩散; - **排除了「复用已有 `Outcome` 分类器当产出方」**——`reflection._classify` 是拿 valence 变化判 `annoyed` 的,valence 依赖它就成环。正确链条是 `产出方 → valence → outcome → dominance`,现在断在根上。 ## Acceptance criteria - [ ] **先落容错**:`drain_delta` 之后、compress 失败时不得丢原文。按 ADR-0009 原文降级为「原样转存低置信 tentative + 标记待重试」,或等价地把原始 delta 重新入库。补一条「LLM 抛异常后原文仍在」的测试。 - [ ] Delta 压缩的抽取 schema 新增互动极性字段,沿用既有 fail-closed 风格(字段缺失/类型非法时取中性值,不猜测)。 - [ ] 接线两个 `update_fast_state` 调用点传入 `valence_raw_delta`;慢层 per-user 同步接上。 - [ ] **验收必须包含「`annoyed` 在端到端里真的出现一次」**——否则很容易只把方程接上、三态仍然只跑两态。这条是本票最容易假通过的地方:`landed`/`fell-flat` 在 valence 恒 0 时也能出现,光看「测试全绿」区分不出来。 - [ ] 补一条守卫,锁住「`valence_raw_delta` 至少有一个非零生产调用点」——防止未来重构又把产出方摘掉而无人发现(同本仓「穷举守卫」先例,ADR-0010 issue #83 节背书)。 - [ ] 顺带确认 mood_congruence 的 valence 维在接上产出方后真的开始参与排序(此前恒等于 0 相比,零贡献)。 ## Not in scope - 不做「未获回应升级」那条 valence 输入源(查漏判为**留痕**,在文档批处理)。 - 不碰 `send` 失败兜底(另一张票)。 - 不做任何结构调整。
Yushu closed this issue 2026-07-30 06:16:09 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ProjectKuma/arise#94
No description provided.