Skip to content

🐛 fix(sidecar): 编排记忆批四缺陷——evidence 脱敏通道/carriedBatches/routine 键域/调度隔离 (#449-#452) - #464

Merged
CavinHuang merged 5 commits into
mainfrom
fix/449-452-memory-routine-hardening
Aug 22, 2026
Merged

🐛 fix(sidecar): 编排记忆批四缺陷——evidence 脱敏通道/carriedBatches/routine 键域/调度隔离 (#449-#452)#464
CavinHuang merged 5 commits into
mainfrom
fix/449-452-memory-routine-hardening

Conversation

@CavinHuang

Copy link
Copy Markdown
Owner

概述

修复 PR #445(编排记忆批)引入或暴露的四个 sidecar 缺陷:#449 / #450 / #451 / #452。每个修复独立 commit,各自带回归测试钉死。

逐项说明

#449 evidence quote 脱敏修错字段,密钥仍明文落盘

sanitizeEvidenceQuote 只过滤从不落盘的 candidate.evidence.quote;真正进 frontmatter 的是 evidence_refs[].quote(YAML.stringify 全量落盘后经 memory.read 回吐 prompt)。

  • 新增 memory-v2/redact.tscontainsSecret + redactEvidenceQuote 共享模块
  • markdown-store 四个 evidence_refs 落盘点统一过滤:writeEntryupdateEntryStatusupdateEntry 合并、writePending
  • 删除 command-service 内无效的 sanitizeEvidenceQuote
  • 测试:remember 端到端断言 frontmatter 无密钥原文 + pending 路径 + updateEntry/updateEntryStatus 合并路径

#450 carriedBatches 连败丢暂存批 + skip 路径吞批

runExtraction 开头 delete 暂存后 catch 里 get() 恒为空——两轮连续失败即永久丢失更早的暂存批。

  • catch 改用开头取出的局部 carriedset(threadId, [...carried, input.items])
  • 新增 restowCarried:skip(main_agent 已显式记忆)与幂等短路等未实际提取的提前返回路径把已取出的暂存批退回
  • 补充暂存 Map 生命周期注释与测试专用读取 seam
  • 测试:连败保留 → skip 退回 → 成功清空四阶段回归

#451 routine 日期键域不统一

PR#445 只改了 services/routine 内三处 today(),UI 与 agent 主路径两处仍是 UTC 键:当地 00:00–05:00 REGENERATE 写昨日文件、晚间读空。

  • rpc/routine-handlers.tsagent-runtime/tools/routine/create-routine-tools.ts 统一改用 localDateKey
  • 测试:固定时钟 + 固定时区钉死 routine_read 默认 / routine_update / GET_TODAY / REGENERATE 四条路径落在本地日历日文件(旧实现下全红)
  • 注:bun test 进程固定按 UTC 且时区缓存经不起 delete 后重设,测试内恢复时区必须走显式赋值

#452 存量永假 cron job 毒化整轮调度刷新

PR#445 新增的 feasibility 校验对存量升级数据(旧版放行的永假 job,nextRunAt=null)抛错,而 refresh 先 clearSchedules 再无隔离遍历——一个坏 job 清光其余全部定时器且每次刷新复现。

  • getNextAutomationRunAt 对无效/永假 schedule 返回 null 跳过调度而非抛;创建/改期入口仍由 validate 显式拒绝
  • scheduleJob 整体 try/catch 隔离:单 job 失败记 error 日志后跳过
  • cronDateFeasible 与 matchCronExpression 统一 AND 语义:0 9 31 2 1 类表达式判永假;AND 下 dow 无法使可行组合永假,可行性只由 dom×month 决定
  • 测试:存量索引注入两个坏 job + 一个好 job → start/refresh 好 job 正常调度、坏 job 被跳过(旧实现下红)

验证

  • bun run --filter @lume/sidecar typecheck 通过
  • 触及模块 8 个测试文件 55 用例全绿;关键用例做过旧实现反向验证(stash 还原后确认变红)

Fixes #449
Fixes #450
Fixes #451
Fixes #452

sanitizeEvidenceQuote 只过滤从不落盘的 candidate.evidence.quote,真正进
frontmatter 的是 evidence_refs[].quote(writeEntry/writePending/updateEntry
等写入点 YAML.stringify 全量落盘,经 memory.read 回吐 agent prompt)。

- 新增 memory-v2/redact.ts:containsSecret + redactEvidenceQuote 共享模块
- markdown-store 四个 evidence_refs 落盘点(writeEntry / updateEntryStatus /
  updateEntry 合并 / writePending)序列化前逐 ref 过滤密钥,命中替换占位符
- 删除 command-service 内无效的 sanitizeEvidenceQuote 及其本地 containsSecret

Fixes #449
runExtraction 开头 delete 暂存后,catch 里 get() 恒为 undefined,只放回
当轮 items——两轮连续失败即永久丢失更早的暂存批,复刻了要消灭的静默丢轮。

- catch 改用开头取出的局部 carried:set(threadId, [...carried, input.items])
- 新增 restowCarried:skip(main_agent 已显式记忆)/ 幂等短路等未实际提取的
  提前返回路径把已取出的暂存批退回,不再随 cursor 前进被静默消费丢弃
- 补充 carriedBatches 生命周期注释;新增测试专用读取 seam 与回归测试
  (连败保留、skip 退回、成功清空四阶段)

Fixes #450
PR#445 只把 services/routine 内三处 today() 换成本地日历日键,漏掉两处主路径:
- rpc/routine-handlers.ts(GET_TODAY 读 readRoutine(today())、REGENERATE 生成)
- agent-runtime/tools/routine/create-routine-tools.ts(routine_read 默认今天、
  routine_update、routine_regenerate)

UTC 键与本地键混用:当地 00:00-05:00 之间 REGENERATE 写昨日文件、晚间读空。
两处统一改用 routine-date.ts 的 localDateKey。

测试:
- routine-date.test.ts:切时区钉死本地键 ≠ UTC 键 + 补零行为
- today-key.test.ts:固定时钟 + UTC+14 时区,钉死 routine_read 默认 /
  routine_update / GET_TODAY / REGENERATE 四条路径落在本地日历日文件
- 既有 routine-tools.test.ts 的期望键同步改为 localDateKey

Fixes #451
)

PR#445 为 validateAutomationSchedule 新增 cronDateFeasible 永假组合即抛,
但未考虑存量升级路径:旧版放行的永假 job(nextRunAt=null)在 scheduleJob
内触发 throw,refresh 先 clearSchedules 再遍历且无隔离——一个坏 job 清光
其余全部定时器,每次刷新复现。

- getNextAutomationRunAt 对无效/永假 schedule 返回 null 跳过调度而非抛;
  创建/改期入口仍由 validateAutomationSchedule 显式拒绝
- scheduleJob 拆出 inner 并整体 try/catch 隔离:单个坏 job 记 error 日志
  (automation.schedule_job_failed)后跳过,不影响其余 job
- cronDateFeasible 与 matchCronExpression 统一 AND 语义:dow 受限不再直接
  放行, 类表达式判永假;AND 下 dow 无法使可行组合永假,
  可行性只由 dom×month 决定

测试:
- feasible AND 反例/正例、getNext null 化(永假 cron / 无效时区 / 脏数据)
- 存量索引注入两个坏 job + 一个好 job → start/refresh 好 job 正常调度、
  坏 job 被跳过;旧实现下该测试红

Fixes #452
@CavinHuang
CavinHuang merged commit 01df253 into main Aug 22, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment