issue #135: 新增忘记我命令——清短期记忆 #142

Merged
Yushu merged 1 commit from feat/135-forget-me-command into main 2026-08-17 02:19:38 +00:00
Member

Closes #135

实现范围

新增"忘记我"命令,仿两条同意命令(issue #71/ADR-0027)的形状——_command_matcher 先例、自服务、不加权限校验,谁发的命令就清谁自己的短期记忆。严格按 ADR-0010 决策节原文锁定范围,只清三个短期状态:

  • storage.PersistentStorage.drain_delta(chat_id)(Delta 缓冲,已有方法,直接复用)
  • Debouncer.discard_all(chat_id)(去抖批次,新增方法)
  • 取消该 chat_id 的待执行 flush 任务(runtime_state._cancel_pending_flush,新增函数)

不删长期画像/事件/关系/向量,不碰 Outbox,不加经济 hook 前置钩子——均按 AC 明确要求。

群聊作用域裁定(AC 要求本片自行裁定并留痕的开放问题)

仅私聊生效,群聊场景直接拒绝执行任何清理,回复引导语说明局限(不照搬两条同意命令"这个要私聊我说才算"的字面话术——私聊/群聊短期缓冲完全不相交,照搬会构成误导)。

依据(详见 docs 分支 ADR-0010 issue #135 更新节,本地已提交不推送):

  1. AC 原文本身就是用户级框架:"谁发的命令就清谁自己的短期记忆"——chat_id 只有在私聊场景才与唯一使用者一一对应,群聊没有唯一的"谁"。
  2. 技术范围约束drain_delta 是 DB 层"先删后读",pending flush 取消是 Task 级操作,两者都做不到 per-sender 过滤;AC 要求直接复用现有实现,不新增 API。
  3. 群聊 Delta 缓冲按设计跨多个 sender_id:无门槛整体清空会让一人的指令波及全群共享内容,且没有先例支持"无门槛动作永久影响整个群共享状态"这种模式。

裁定经过对抗式验证,中途否掉了一版"类比 ADR-0010 否决的全局硬删 nuke"的论证(该类比不成立:nuke 针对的是已落库的长期共享记忆,ADR 原文把"仅清短期"当作 nuke 问题的解法而非翻版)——最终依据换成了上面三条不借用该类比的独立理由。

一处刻意偏离 AC 字面指令

AC 要求把 explain.py 与 ADR-0010 issue #83 更新节里"ADR-0010 的忘记我一旦落地,第一条路径立刻变成可达"这句话改成"现在已可达"。本 PR 没有照做:经核实,忘记我命令严格按"仅清短期,不删长期"实现,从未触碰 EventModel/why 可见性闸讨论的对象),所以命令落地并没有让那条路径变可达——它依然可证不可达。按 AC 字面要求写"现在已可达"会是一句可查证为假的陈述,与同一份 ADR 自己强调的"写清当下不可达比写一个听起来合理但错误的理由重要"直接冲突,因此保留准确表述并订正了原来的预测性表述(两处均已注明订正原因)。

验证

  • 新增 13 个单元测试(test_forget_me_command.py 9 个覆盖私聊/群聊两组行为,test_runtime_state.py 4 个覆盖 _cancel_pending_flushtest_debounce.py 新增 4 个覆盖 discard_all),加上既有枚举穷举守卫同步。
  • 变异测试:4 处新守卫逐一验证(群聊判定翻转、discard_all/_cancel_pending_flush 的 pop→get、task.cancel() 移除),全部被现有测试正确捕获,mutation 后均已用备份精确还原并核对哈希。
  • 全量测试 1824 个全绿,ruff check/ruff format 干净,ty 类型检查确认无新增诊断(仅命中仓库既有、与本次改动无关的历史问题)。
  • 两轴 review(Standards + Spec)+ 对抗式 Verify:3 条发现全部 CONFIRMED 并已修复(runtime_state.py 缺两行空行的格式问题;AC 要求的"checkpoint 在本仓无指涉"此前未显式记下,已补;群聊裁定原本漏了最直接的 AC 文本依据,已补)。

文档同步

docs 分支(本地已提交,不推送):ADR-0010 追加更新节记录本次落地 + 群聊作用域裁定 + checkpoint 说明;订正 issue #83 更新节里那句预测性表述;design.md 补一句说明忘记我不在"上线路线"六阶段之列。explain.py 模块 docstring 同步订正。CONTEXT.md/design.md 现有的忘记我描述本身已经是目标态,未改动。

🤖 Generated with Claude Code

Closes #135 ## 实现范围 新增"忘记我"命令,仿两条同意命令(issue #71/ADR-0027)的形状——`_command_matcher` 先例、自服务、不加权限校验,谁发的命令就清谁自己的短期记忆。严格按 ADR-0010 决策节原文锁定范围,只清三个短期状态: - `storage.PersistentStorage.drain_delta(chat_id)`(Delta 缓冲,已有方法,直接复用) - `Debouncer.discard_all(chat_id)`(去抖批次,新增方法) - 取消该 chat_id 的待执行 flush 任务(`runtime_state._cancel_pending_flush`,新增函数) 不删长期画像/事件/关系/向量,不碰 Outbox,不加经济 hook 前置钩子——均按 AC 明确要求。 ## 群聊作用域裁定(AC 要求本片自行裁定并留痕的开放问题) **仅私聊生效,群聊场景直接拒绝执行任何清理**,回复引导语说明局限(不照搬两条同意命令"这个要私聊我说才算"的字面话术——私聊/群聊短期缓冲完全不相交,照搬会构成误导)。 依据(详见 docs 分支 ADR-0010 issue #135 更新节,本地已提交不推送): 1. **AC 原文本身就是用户级框架**:"谁发的命令就清谁自己的短期记忆"——`chat_id` 只有在私聊场景才与唯一使用者一一对应,群聊没有唯一的"谁"。 2. **技术范围约束**:`drain_delta` 是 DB 层"先删后读",pending flush 取消是 Task 级操作,两者都做不到 per-sender 过滤;AC 要求直接复用现有实现,不新增 API。 3. **群聊 Delta 缓冲按设计跨多个 sender_id**:无门槛整体清空会让一人的指令波及全群共享内容,且没有先例支持"无门槛动作永久影响整个群共享状态"这种模式。 裁定经过对抗式验证,中途否掉了一版"类比 ADR-0010 否决的全局硬删 nuke"的论证(该类比不成立:nuke 针对的是已落库的长期共享记忆,ADR 原文把"仅清短期"当作 nuke 问题的解法而非翻版)——最终依据换成了上面三条不借用该类比的独立理由。 ## 一处刻意偏离 AC 字面指令 AC 要求把 `explain.py` 与 ADR-0010 issue #83 更新节里"ADR-0010 的忘记我一旦落地,第一条路径立刻变成可达"这句话改成"现在已可达"。**本 PR 没有照做**:经核实,忘记我命令严格按"仅清短期,不删长期"实现,从未触碰 `EventModel`(`/why` 可见性闸讨论的对象),所以命令落地并没有让那条路径变可达——它依然可证不可达。按 AC 字面要求写"现在已可达"会是一句可查证为假的陈述,与同一份 ADR 自己强调的"写清当下不可达比写一个听起来合理但错误的理由重要"直接冲突,因此保留准确表述并订正了原来的预测性表述(两处均已注明订正原因)。 ## 验证 - 新增 13 个单元测试(`test_forget_me_command.py` 9 个覆盖私聊/群聊两组行为,`test_runtime_state.py` 4 个覆盖 `_cancel_pending_flush`,`test_debounce.py` 新增 4 个覆盖 `discard_all`),加上既有枚举穷举守卫同步。 - 变异测试:4 处新守卫逐一验证(群聊判定翻转、`discard_all`/`_cancel_pending_flush` 的 pop→get、`task.cancel()` 移除),全部被现有测试正确捕获,mutation 后均已用备份精确还原并核对哈希。 - 全量测试 1824 个全绿,`ruff check`/`ruff format` 干净,`ty` 类型检查确认无新增诊断(仅命中仓库既有、与本次改动无关的历史问题)。 - 两轴 review(Standards + Spec)+ 对抗式 Verify:3 条发现全部 CONFIRMED 并已修复(`runtime_state.py` 缺两行空行的格式问题;AC 要求的"checkpoint 在本仓无指涉"此前未显式记下,已补;群聊裁定原本漏了最直接的 AC 文本依据,已补)。 ## 文档同步 docs 分支(本地已提交,不推送):ADR-0010 追加更新节记录本次落地 + 群聊作用域裁定 + checkpoint 说明;订正 issue #83 更新节里那句预测性表述;design.md 补一句说明忘记我不在"上线路线"六阶段之列。`explain.py` 模块 docstring 同步订正。CONTEXT.md/design.md 现有的忘记我描述本身已经是目标态,未改动。 🤖 Generated with [Claude Code](https://claude.com/claude-code)
仿两条同意命令的形状(_command_matcher先例,自服务、不加权限校验),仅清
ADR-0010决策节原文限定的三个短期状态,不删长期画像/事件/关系/向量。

群聊场景直接拒绝执行(本片显式裁定,ADR/CONTEXT/design均未定这个作用域问题):
AC本身给这条命令定的框架是"谁发的命令就清谁自己的短期记忆",chat_id只有在私聊
才与唯一使用者一一对应;且群聊Delta缓冲按设计跨多个sender_id,本命令锁定复用
的三个清理操作都只到chat_id粒度,无门槛整体清空会让一人的指令波及全群共享内容。

新增 Debouncer.discard_all 与 runtime_state._cancel_pending_flush 两个小工具方法,
均配独立单元测试;忘记我命令的私聊/群聊两组行为各有专门测试文件覆盖。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Yushu merged commit c82d7ef24e into main 2026-08-17 02:19:38 +00:00
Yushu deleted branch feat/135-forget-me-command 2026-08-17 02:19:39 +00:00
Sign in to join this conversation.
No description provided.