[PRD] arise register_callback(用户设到点提醒)落地 #62

Closed
opened 2026-07-24 09:10:02 +00:00 by KumaAgent · 0 comments
Member

Problem Statement

从终端用户角度:用户经常会顺口让机器人"半小时后提醒我关火""明天早上8点提醒我交作业",但目前 arise 完全没有能力记住这类带具体触发时间的请求——它只能在当轮回答,之后就把这件事忘得一干二净,用户必须自己记着到点再来问。

从架构角度:这个缺口其实已经不该再存在了。深挖任务委托(issue #52 PRD → #53-#56)实现期顺带把 Callback 建成了一个真正通用的送回抽象——持久化、到期扫描、无门控直接送回,trigger_source 字段从一开始就是为"未来还会有别的触发源"设计的,CallbackRecord.fire_at 字段也从一开始就支持非空的真实到点时间(当前唯一生产者"任务完成"用的是 fire_at=None 的"立即到期"这一种取值)。CONTEXT.md"回调(Callback)"一节从最初设计起就明确写着"触发源不止'到点'一种:register_callback……为其一"——地基已经等在那里,只是这个工具本身从未被实现。

从维护者角度:如果这次不做,Callback 这条通用管线就永远只有一个真实生产者验证过,"通用"这个说法就只是理论上的。用一个真正独立、语义不同的第二生产者(时间到点 vs 任务完成)来验证这条管线是否真的不需要为新生产者改动,是这次实现最有价值的副产物。

Solution

新增 register_callback(content, fire_at) / cancel_callback(callback_id) 两个 core 原生工具(同 delegate_task/cancel_delegate_task 先例,不经工具港)。模型识别到用户请求一个带具体触发时间的提醒时,自己基于当前消息时间戳推算出目标时间(ISO8601),调用 register_callback 写入一条 trigger_source="user_reminder" 的 Callback 记录;到点后由已有的、零改动的 _callback_scan/run_callback() 管线无门控送回,模型用平时语气自然说出来。用户改主意时,模型调用 cancel_callback 撤销——为了让这个取消在几天后依然可用,新增一段纯函数渲染,把当前 chat 待定的 user_reminder 记录(含 id)纳入冻结快照,供模型跨轮次引用。

User Stories

用户视角:设提醒

  1. 作为用户,我希望能直接跟机器人说"半小时后提醒我关火",它就记住了,不需要学一套额外的指令语法。
  2. 作为用户,我希望"明天早上8点提醒我交作业"这种带具体日期的表达,机器人也能正确理解到点时间。
  3. 作为用户,我希望机器人到点后是真的主动找我说这件事,而不是要我自己再去问它才想起来。
  4. 作为用户,我希望即使机器人进程期间短暂重启过,事后也不会忘记我设过的这个提醒——它应该在恢复后继续认这件事、照常到点触发。
  5. 作为用户,我希望到点提醒送达时,机器人是用它平时说话的语气自然地讲出来,不是照本宣科地念一遍我当时说的原话。
  6. 作为用户,我希望我可以同时设好几个不同的提醒,它们互不干扰,都能各自准时触发。
  7. 作为群聊用户,我希望在群里设的提醒送到这个群,不会送错到别的会话。

用户视角:取消提醒

  1. 作为用户,我如果改主意了("算了这个提醒不用了"),我希望机器人能听懂并真的取消掉,不会到点还是照样提醒我。
  2. 作为用户,我希望取消是针对具体那一条提醒的,不会因为我说"取消提醒"就把我设的其它提醒也一并误删。
  3. 作为用户,我希望即使这个提醒是好几天前设的、早就不在最近聊天记录里了,我现在说"取消"机器人也知道我在说的是哪一条,不需要我把内容原样复述一遍给它核对。

用户视角:边界与信任

  1. 作为用户,我希望这个提醒不会被机器人的"沉默预算"或"要不要主动开口"这类主动性判断给压下去——这是我明确让它做的事,它应该说到做到,不是它自己决定要不要理我。
  2. 作为用户,我希望机器人不会接受一个已经过去的时间当提醒时间(比如我一不小心说了个已经过去的日期)——它应该能意识到这个时间点已经过去,提示我而不是照单全收。
  3. 作为用户,我希望我不会不小心让机器人给我设几十个提醒堆在那——如果我确实一口气设了非常多,机器人应该有个合理的上限,不是无限制地照单全收。

Host 部署者视角

  1. 作为部署者,我希望这个功能复用已有的 Callback 送回管线,不会因为新增这个功能而新开一条独立的调度/存储/送回代码路径,增加维护面。
  2. 作为部署者,我希望送回时用的还是正常的、带完整记忆/关系网/情感态上下文的对话能力,不是一个信息量被砍掉的阉割版通知。
  3. 作为部署者,我希望这个功能跟深挖任务委托的完成送回互不干扰——两者同时存在于同一个 chat 时,各自的记录只会各自被送回/取消,不会串。

维护者/贡献者视角

  1. 作为维护者,我希望"给定当前待定提醒记录列表,渲染成模型可读的清单文本"是一个不依赖真实存储/时钟的纯函数,能直接构造固定输入断言输出。
  2. 作为维护者,我希望"这个 fire_at 是不是已经过去了"这类校验逻辑本身是纯函数,能直接构造固定输入断言,不需要真实时钟。
  3. 作为维护者,我希望 register_callback/cancel_callbackRuntimeLoop 里的测试方式跟现有 delegate_task/cancel_delegate_task 一样,直接喂脚本化对话断言效果,不需要真的等待到点或起后台任务。
  4. 作为维护者,我希望这次不需要对 _callback_scan/_deliver_callback/run_callback()/is_due/render_callback_directive 这几个既有模块做任何改动——如果实现期发现真的需要改这几个文件,这本身就是一个值得先停下核实"通用抽象是不是真的通用"的信号。

验收标准视角

  1. 作为验收标准,我希望 register_callback 产出的记录 trigger_source 取值明确区别于深挖任务委托的 task_completioncancel_callback 只会撤销匹配来源/id 的那一条,不会误伤深挖任务委托正在待送回的记录。
  2. 作为验收标准,我希望送回时机真实按 fire_at 到点触发(受限于既有扫描间隔的粒度,不要求秒级精确)。
  3. 作为验收标准,我希望这两个新工具不需要新的能力位(capability)声明、也不受渐进解锁门控——延续 delegate_task 先例:用户显式请求触发的功能,不适用"新部署更保守"的理由。

Implementation Decisions

新增核心工具

  • register_callback(content, fire_at):core 原生工具(同 delegate_task/note_pending_intent 先例,不经工具港,不新增能力位)。fire_at 是 ISO8601 时间字符串,由模型自己基于当前消息真实时间戳推算得出——前处理 port 已经把真实时间戳带进每条消息(ADR-0018),前台工具调用有活的推理能力,不新增一层类似 Delta 压缩管线那种确定性正则时间解析(那是异步批处理场景的专属方案,这里不适用)。
  • 参数校验(fail-closed):fire_at 解析失败,或早于/等于当前时间——拒绝,工具结果返回一句可读错误交给模型组织语言告知用户,不静默创建一条永远不会触发的记录,也不做"帮用户纠正成明天这个点"式的猜测。
  • cancel_callback(callback_id):core 原生工具。callback_id 来自下述"待定提醒渲染"——模型从渲染文本里读到具体 id 再引用。找不到匹配记录(id 不存在,或存在但不属于 user_reminder 来源)——fail-closed 无操作,不报错阻断对话,同 cancel_delegate_task 先例。
  • 新增一个 trigger_source 常量(如 USER_REMINDER_TRIGGER_SOURCE = "user_reminder"),仿 delegate_task.py::TASK_COMPLETION_TRIGGER_SOURCE 先例——各生产者自己持有自己的常量,callback.py 本身不维护生产者清单。取消时只按这个来源过滤,不触碰深挖任务委托的待送回记录(同 issue #56 已建立的"不误删其它来源"先例)。
  • 两个工具恒可见,不受渐进解锁门控;同时加入既有 RUN_LIMIT_EXEMPT_TOOL_NAMES(登记/撤销一次提醒不是当轮"推理",同 delegate_task/cancel_delegate_task 归类理由)。

待定提醒渲染(新增,唯一需要往复用管线里"加一段"的地方)

  • 新增一个纯函数(仿 pending_intent.py::render_pending_intents 先例),把当前 chat 的待定 user_reminder 记录渲染进冻结快照——挂进 _full_frozen_snapshot() 既有六段拼装之后的新增第七段,只在存在待定记录时产出内容(同其余快照分段"无数据即空字符串"的一贯风格),内容含 callback_id(供 cancel_callback 引用)、内容摘要、fire_at
  • 只渲染 trigger_source="user_reminder" 的记录——task_completion 来源的待送回记录不在这段渲染范围内:那类记录生命周期通常是"当轮登记、后台跑完、下一次扫描前送回",跨度短,用户中途不需要查询/取消进度(取消深挖任务走既有 cancel_delegate_task,走的是任务登记表而不是这条渲染)。这个区分是本次的一个明确判断,不是"新触发源=自动也要渲染"的机械推广。

反滥用静态上限

  • 新增静态 config 项(如 arise_max_pending_callbacks_per_chat),限制单 chat 同时存在的 user_reminder 待定记录数——同仓库既有"阈值三层分类"静态 config 层惯例(MAX_SENDS_PER_TURN/MAX_KNOWLEDGE_PER_TURN/MAX_EDITS_PER_MESSAGE 同类先例)。超限时 register_callback 返回错误提示,不静默丢弃、不静默覆盖最旧的一条。

明确不改动的既有管线(防止实现期误以为需要碰这些)

  • CallbackRecord/CallbackStoragePort/is_due/render_callback_directivecallback.py):零改动,fire_at 字段本就为非空真实到点时间预留。
  • _callback_scan/_deliver_callback(调度驱动):零改动,已经是"扫全体待定记录、按 is_due 过滤、忙时 defer"的通用实现,不认识任何具体 trigger_source
  • RuntimeLoop.run_callback():零改动,履约送回统一走这一个入口,复用完整六段冻结快照 + 独立合成指令的既有组装方式。

Testing Decisions

好的测试只测外部可观察行为(工具调用产生的记录状态、送回内容/时机、取消的最终效果),不测内部实现细节。

  • 纯函数register_callback/cancel_callback 的参数校验(过去时间拒绝、格式错误拒绝)、待定提醒渲染(多条记录/零记录空字符串/字段完整性),仿 pending_intent.py 既有测试模式。
  • RuntimeLoop 前台工具处理register_callback/cancel_callback 直接喂 RuntimeLoop.run() 脚本化对话断言效果(登记成功返回 id、超限拒绝、取消成功、取消不存在的 id fail-closed、跨 chat 隔离),仿现有 test_delegate_task_tools.py 模式。
  • 集成验证(复用管线的直接证据):一条 register_callback 登记的记录能被既有 _callback_scan/run_callback() 不加任何改动地正确送回——仿 test_callback_scan_e2e.py 已有的端到端模式,换一个生产者、走同一条管线。这条测试本身就是"Callback 抽象真的通用"这个论断的证据。
  • 取消隔离cancel_callback 只撤销 user_reminder 来源记录,不误伤同一 chat 下 task_completion 来源的待送回记录(构造两者同时存在的场景),仿 issue #56 已验证过的"不误删其它来源"测试先例。
  • 崩溃恢复语义:验证进程重启后待定 user_reminder 记录原样还在(同 issue #56 已验证的 Callback 持久化不变量,这次换一个生产者再验一遍,防止未来有人把某个生产者的记录错误地做成非持久化)。

Out of Scope

  • 修改/替换既有 Callback 送回管线代码本身_callback_scan/_deliver_callback/run_callback()/is_due/render_callback_directive)——本次是验证这条管线设计时就预留好的"新生产者只需新增,不改地基",不是重新设计它。
  • 重复提醒("每天早上8点提醒我"这类周期性/RRULE 语义):CONTEXT.md 对 register_callback 的既定定义是"纯 time 模式"的一次性到点,周期语义涉及时区/日历处理,是完全不同量级的功能,不在本次范围。
  • 提醒内容的确定性正则时间解析兜底层:决定用模型直接基于当前时间戳推算 fire_at,不建类似 Delta 压缩管线那种正则解析层,见 Implementation Decisions。
  • 深挖任务委托相关功能:已完成(issue #52/#53-#56),及其"灰度可一键关"缺口(已发 issue #61 独立跟踪)——本次不涉及。
  • ADR-0010 完整运营面(/cost//why//why_query//diagnose、六池成本治理)、习得贴纸(ADR-0024)、跨平台资料拉取(ADR-0027)、记忆深度搜索(ADR-0031)、mood_congruence(ADR-0009 更新)、环境遥测(ADR-0014 更新):均为独立条目,不在本次顺带实现。

Further Notes

  • 这是 Callback 通用抽象(issue #53)完成以来第一次迎来第二个真实生产者,也是验证它是否真的通用的第一次机会——Implementation Decisions 里刻意列出"零改动"的既有模块清单,就是这次验收的核心标准之一:如果实现期发现真的绕不开要改 callback.py/_callback_scan 本身,应该先停下来核实是不是通用抽象本身有设计缺陷,而不是想当然地加 trigger_source 特判分支糊过去。
  • 待定提醒渲染这个新增点是"按需判断"而非"机械推广"的产物——task_completion 不需要渲染、user_reminder 需要,理由是两者生命周期跨度不同。如果未来 Callback 出现第三个触发源,需要重新做一次同样的判断,不能假设"新触发源=自动也要渲染进上下文"。
  • arise_max_pending_callbacks_per_chat 的具体数字,同仓库既有"阈值三层分类"原则(ADR-0011),推迟到真实使用数据标定,本 PRD 不预先钉死。
## Problem Statement 从终端用户角度:用户经常会顺口让机器人"半小时后提醒我关火""明天早上8点提醒我交作业",但目前 arise 完全没有能力记住这类带具体触发时间的请求——它只能在当轮回答,之后就把这件事忘得一干二净,用户必须自己记着到点再来问。 从架构角度:这个缺口其实已经不该再存在了。深挖任务委托(issue #52 PRD → #53-#56)实现期顺带把 Callback 建成了一个真正通用的送回抽象——持久化、到期扫描、无门控直接送回,`trigger_source` 字段从一开始就是为"未来还会有别的触发源"设计的,`CallbackRecord.fire_at` 字段也从一开始就支持非空的真实到点时间(当前唯一生产者"任务完成"用的是 `fire_at=None` 的"立即到期"这一种取值)。CONTEXT.md"回调(Callback)"一节从最初设计起就明确写着"触发源不止'到点'一种:`register_callback`……为其一"——地基已经等在那里,只是这个工具本身从未被实现。 从维护者角度:如果这次不做,Callback 这条通用管线就永远只有一个真实生产者验证过,"通用"这个说法就只是理论上的。用一个真正独立、语义不同的第二生产者(时间到点 vs 任务完成)来验证这条管线是否真的不需要为新生产者改动,是这次实现最有价值的副产物。 ## Solution 新增 `register_callback(content, fire_at)` / `cancel_callback(callback_id)` 两个 core 原生工具(同 `delegate_task`/`cancel_delegate_task` 先例,不经工具港)。模型识别到用户请求一个带具体触发时间的提醒时,自己基于当前消息时间戳推算出目标时间(ISO8601),调用 `register_callback` 写入一条 `trigger_source="user_reminder"` 的 Callback 记录;到点后由**已有的、零改动的** `_callback_scan`/`run_callback()` 管线无门控送回,模型用平时语气自然说出来。用户改主意时,模型调用 `cancel_callback` 撤销——为了让这个取消在几天后依然可用,新增一段纯函数渲染,把当前 chat 待定的 `user_reminder` 记录(含 id)纳入冻结快照,供模型跨轮次引用。 ## User Stories **用户视角:设提醒** 1. 作为用户,我希望能直接跟机器人说"半小时后提醒我关火",它就记住了,不需要学一套额外的指令语法。 2. 作为用户,我希望"明天早上8点提醒我交作业"这种带具体日期的表达,机器人也能正确理解到点时间。 3. 作为用户,我希望机器人到点后是真的主动找我说这件事,而不是要我自己再去问它才想起来。 4. 作为用户,我希望即使机器人进程期间短暂重启过,事后也不会忘记我设过的这个提醒——它应该在恢复后继续认这件事、照常到点触发。 5. 作为用户,我希望到点提醒送达时,机器人是用它平时说话的语气自然地讲出来,不是照本宣科地念一遍我当时说的原话。 6. 作为用户,我希望我可以同时设好几个不同的提醒,它们互不干扰,都能各自准时触发。 7. 作为群聊用户,我希望在群里设的提醒送到这个群,不会送错到别的会话。 **用户视角:取消提醒** 8. 作为用户,我如果改主意了("算了这个提醒不用了"),我希望机器人能听懂并真的取消掉,不会到点还是照样提醒我。 9. 作为用户,我希望取消是针对具体那一条提醒的,不会因为我说"取消提醒"就把我设的其它提醒也一并误删。 10. 作为用户,我希望即使这个提醒是好几天前设的、早就不在最近聊天记录里了,我现在说"取消"机器人也知道我在说的是哪一条,不需要我把内容原样复述一遍给它核对。 **用户视角:边界与信任** 11. 作为用户,我希望这个提醒不会被机器人的"沉默预算"或"要不要主动开口"这类主动性判断给压下去——这是我明确让它做的事,它应该说到做到,不是它自己决定要不要理我。 12. 作为用户,我希望机器人不会接受一个已经过去的时间当提醒时间(比如我一不小心说了个已经过去的日期)——它应该能意识到这个时间点已经过去,提示我而不是照单全收。 13. 作为用户,我希望我不会不小心让机器人给我设几十个提醒堆在那——如果我确实一口气设了非常多,机器人应该有个合理的上限,不是无限制地照单全收。 **Host 部署者视角** 14. 作为部署者,我希望这个功能复用已有的 Callback 送回管线,不会因为新增这个功能而新开一条独立的调度/存储/送回代码路径,增加维护面。 15. 作为部署者,我希望送回时用的还是正常的、带完整记忆/关系网/情感态上下文的对话能力,不是一个信息量被砍掉的阉割版通知。 16. 作为部署者,我希望这个功能跟深挖任务委托的完成送回互不干扰——两者同时存在于同一个 chat 时,各自的记录只会各自被送回/取消,不会串。 **维护者/贡献者视角** 17. 作为维护者,我希望"给定当前待定提醒记录列表,渲染成模型可读的清单文本"是一个不依赖真实存储/时钟的纯函数,能直接构造固定输入断言输出。 18. 作为维护者,我希望"这个 `fire_at` 是不是已经过去了"这类校验逻辑本身是纯函数,能直接构造固定输入断言,不需要真实时钟。 19. 作为维护者,我希望 `register_callback`/`cancel_callback` 在 `RuntimeLoop` 里的测试方式跟现有 `delegate_task`/`cancel_delegate_task` 一样,直接喂脚本化对话断言效果,不需要真的等待到点或起后台任务。 20. 作为维护者,我希望这次不需要对 `_callback_scan`/`_deliver_callback`/`run_callback()`/`is_due`/`render_callback_directive` 这几个既有模块做任何改动——如果实现期发现真的需要改这几个文件,这本身就是一个值得先停下核实"通用抽象是不是真的通用"的信号。 **验收标准视角** 21. 作为验收标准,我希望 `register_callback` 产出的记录 `trigger_source` 取值明确区别于深挖任务委托的 `task_completion`,`cancel_callback` 只会撤销匹配来源/id 的那一条,不会误伤深挖任务委托正在待送回的记录。 22. 作为验收标准,我希望送回时机真实按 `fire_at` 到点触发(受限于既有扫描间隔的粒度,不要求秒级精确)。 23. 作为验收标准,我希望这两个新工具不需要新的能力位(capability)声明、也不受渐进解锁门控——延续 `delegate_task` 先例:用户显式请求触发的功能,不适用"新部署更保守"的理由。 ## Implementation Decisions **新增核心工具** - `register_callback(content, fire_at)`:core 原生工具(同 `delegate_task`/`note_pending_intent` 先例,不经工具港,不新增能力位)。`fire_at` 是 ISO8601 时间字符串,由**模型自己基于当前消息真实时间戳推算得出**——前处理 port 已经把真实时间戳带进每条消息(ADR-0018),前台工具调用有活的推理能力,不新增一层类似 Delta 压缩管线那种确定性正则时间解析(那是异步批处理场景的专属方案,这里不适用)。 - 参数校验(fail-closed):`fire_at` 解析失败,或早于/等于当前时间——拒绝,工具结果返回一句可读错误交给模型组织语言告知用户,不静默创建一条永远不会触发的记录,也不做"帮用户纠正成明天这个点"式的猜测。 - `cancel_callback(callback_id)`:core 原生工具。`callback_id` 来自下述"待定提醒渲染"——模型从渲染文本里读到具体 id 再引用。找不到匹配记录(id 不存在,或存在但不属于 `user_reminder` 来源)——fail-closed 无操作,不报错阻断对话,同 `cancel_delegate_task` 先例。 - 新增一个 `trigger_source` 常量(如 `USER_REMINDER_TRIGGER_SOURCE = "user_reminder"`),仿 `delegate_task.py::TASK_COMPLETION_TRIGGER_SOURCE` 先例——各生产者自己持有自己的常量,`callback.py` 本身不维护生产者清单。取消时只按这个来源过滤,不触碰深挖任务委托的待送回记录(同 issue #56 已建立的"不误删其它来源"先例)。 - 两个工具恒可见,不受渐进解锁门控;同时加入既有 `RUN_LIMIT_EXEMPT_TOOL_NAMES`(登记/撤销一次提醒不是当轮"推理",同 `delegate_task`/`cancel_delegate_task` 归类理由)。 **待定提醒渲染(新增,唯一需要往复用管线里"加一段"的地方)** - 新增一个纯函数(仿 `pending_intent.py::render_pending_intents` 先例),把当前 chat 的待定 `user_reminder` 记录渲染进冻结快照——挂进 `_full_frozen_snapshot()` 既有六段拼装之后的新增第七段,只在存在待定记录时产出内容(同其余快照分段"无数据即空字符串"的一贯风格),内容含 `callback_id`(供 `cancel_callback` 引用)、内容摘要、`fire_at`。 - **只渲染 `trigger_source="user_reminder"` 的记录**——`task_completion` 来源的待送回记录不在这段渲染范围内:那类记录生命周期通常是"当轮登记、后台跑完、下一次扫描前送回",跨度短,用户中途不需要查询/取消进度(取消深挖任务走既有 `cancel_delegate_task`,走的是任务登记表而不是这条渲染)。这个区分是本次的一个明确判断,不是"新触发源=自动也要渲染"的机械推广。 **反滥用静态上限** - 新增静态 config 项(如 `arise_max_pending_callbacks_per_chat`),限制单 chat 同时存在的 `user_reminder` 待定记录数——同仓库既有"阈值三层分类"静态 config 层惯例(`MAX_SENDS_PER_TURN`/`MAX_KNOWLEDGE_PER_TURN`/`MAX_EDITS_PER_MESSAGE` 同类先例)。超限时 `register_callback` 返回错误提示,不静默丢弃、不静默覆盖最旧的一条。 **明确不改动的既有管线(防止实现期误以为需要碰这些)** - `CallbackRecord`/`CallbackStoragePort`/`is_due`/`render_callback_directive`(`callback.py`):零改动,`fire_at` 字段本就为非空真实到点时间预留。 - `_callback_scan`/`_deliver_callback`(调度驱动):零改动,已经是"扫全体待定记录、按 `is_due` 过滤、忙时 defer"的通用实现,不认识任何具体 `trigger_source`。 - `RuntimeLoop.run_callback()`:零改动,履约送回统一走这一个入口,复用完整六段冻结快照 + 独立合成指令的既有组装方式。 ## Testing Decisions 好的测试只测外部可观察行为(工具调用产生的记录状态、送回内容/时机、取消的最终效果),不测内部实现细节。 - **纯函数**:`register_callback`/`cancel_callback` 的参数校验(过去时间拒绝、格式错误拒绝)、待定提醒渲染(多条记录/零记录空字符串/字段完整性),仿 `pending_intent.py` 既有测试模式。 - **RuntimeLoop 前台工具处理**:`register_callback`/`cancel_callback` 直接喂 `RuntimeLoop.run()` 脚本化对话断言效果(登记成功返回 id、超限拒绝、取消成功、取消不存在的 id fail-closed、跨 chat 隔离),仿现有 `test_delegate_task_tools.py` 模式。 - **集成验证(复用管线的直接证据)**:一条 `register_callback` 登记的记录能被既有 `_callback_scan`/`run_callback()` **不加任何改动**地正确送回——仿 `test_callback_scan_e2e.py` 已有的端到端模式,换一个生产者、走同一条管线。这条测试本身就是"Callback 抽象真的通用"这个论断的证据。 - **取消隔离**:`cancel_callback` 只撤销 `user_reminder` 来源记录,不误伤同一 chat 下 `task_completion` 来源的待送回记录(构造两者同时存在的场景),仿 issue #56 已验证过的"不误删其它来源"测试先例。 - **崩溃恢复语义**:验证进程重启后待定 `user_reminder` 记录原样还在(同 issue #56 已验证的 Callback 持久化不变量,这次换一个生产者再验一遍,防止未来有人把某个生产者的记录错误地做成非持久化)。 ## Out of Scope - **修改/替换既有 Callback 送回管线代码本身**(`_callback_scan`/`_deliver_callback`/`run_callback()`/`is_due`/`render_callback_directive`)——本次是验证这条管线设计时就预留好的"新生产者只需新增,不改地基",不是重新设计它。 - **重复提醒**("每天早上8点提醒我"这类周期性/RRULE 语义):CONTEXT.md 对 `register_callback` 的既定定义是"纯 time 模式"的一次性到点,周期语义涉及时区/日历处理,是完全不同量级的功能,不在本次范围。 - **提醒内容的确定性正则时间解析兜底层**:决定用模型直接基于当前时间戳推算 `fire_at`,不建类似 Delta 压缩管线那种正则解析层,见 Implementation Decisions。 - **深挖任务委托相关功能**:已完成(issue #52/#53-#56),及其"灰度可一键关"缺口(已发 [issue #61](https://code.srcz.one/ProjectKuma/arise/issues/61) 独立跟踪)——本次不涉及。 - **ADR-0010 完整运营面(`/cost`/`/why`/`/why_query`/`/diagnose`、六池成本治理)、习得贴纸(ADR-0024)、跨平台资料拉取(ADR-0027)、记忆深度搜索(ADR-0031)、mood_congruence(ADR-0009 更新)、环境遥测(ADR-0014 更新)**:均为独立条目,不在本次顺带实现。 ## Further Notes - 这是 Callback 通用抽象(issue #53)完成以来第一次迎来第二个真实生产者,也是验证它是否真的通用的第一次机会——Implementation Decisions 里刻意列出"零改动"的既有模块清单,就是这次验收的核心标准之一:如果实现期发现真的绕不开要改 `callback.py`/`_callback_scan` 本身,应该先停下来核实是不是通用抽象本身有设计缺陷,而不是想当然地加 `trigger_source` 特判分支糊过去。 - 待定提醒渲染这个新增点是"按需判断"而非"机械推广"的产物——`task_completion` 不需要渲染、`user_reminder` 需要,理由是两者生命周期跨度不同。如果未来 Callback 出现第三个触发源,需要重新做一次同样的判断,不能假设"新触发源=自动也要渲染进上下文"。 - `arise_max_pending_callbacks_per_chat` 的具体数字,同仓库既有"阈值三层分类"原则(ADR-0011),推迟到真实使用数据标定,本 PRD 不预先钉死。
Yushu closed this issue 2026-07-25 01:55:37 +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#62
No description provided.