fix(workflows): bound settled run retention - #239
Conversation
somewan820
left a comment
There was a problem hiding this comment.
P1 Must-Fix:extensions/workflows/retention.ts:274 使用 raw JSON.stringify(details) 计算 bytes,但现有 serialization.ts:429-448 的 safeStringify 明确支持 BigInt/cycle。含 BigInt 或 cycle 的合法 workflow result 会在 recordTerminalRun() 中抛错,background path 可能在 resultDelivery.defer() 前失败,blocking path 也可能让已完成 workflow 失败。请使用仓库既有 serializer 或只测量有界字段,并补充 BigInt/cycle delivery 测试。
P2 Should-Fix:dashboardDetails 只返回 activeDetails,而 dashboard.ts:563-577 在 persistence 暂不可用时跳过 non-live run,导致内存中保留的刚完成 projection 从 dashboard 消失。请合并 retained projections,并增加 persistence failure dashboard 测试。静态审查,未运行测试。
agnitum2009
left a comment
There was a problem hiding this comment.
结论:Request Changes
针对"是否缺乏复现测试过程"的问题:是,已确认。并且我做了对抗测试(真实 sandbox 子进程的 E2E),对上一条审查意见给出实测裁决:P1 根因属实但端到端不可达(严重级应降为 Should-Fix),P2 实测成立。
1. 缺乏复现测试(核心问题)
- 新增的 7 个测试全部只对新的
retention.ts类做良性字符串数据的单元测试。测试文件 import 的retention.ts与persistWorkflowDeliveryState均为本 PR 新增,没有任何测试能在 main 上运行并失败——即没有复现缺陷的测试。 - Issue #178 明确要求"压力测试连续完成大量包含 agents/logs 的 runs,证明内存集合有界",本 PR 没有提供扩展层级的压力/回归测试,也没有 main 修复前后的内存增长对比数据。
- Validation 一节承认 3 项 replay 测试在作者环境失败、全仓库有环境基线问题,验证是不完整的。
- 这个缺口不是假设:下面的 P2 就是该缺口的直接产物。
2. P1(jsonBytes 裸 JSON.stringify):根因属实,端到端不可达 —— 降为 Should-Fix
对抗测试结果(基于本 PR 分支,node --test --experimental-strip-types):
- ✅ 单元级确认:
projectWorkflowDetails对含 BigInt 的 result 抛TypeError: Do not know how to serialize a BigInt;WorkflowSettledRunRetention.set对循环引用 result 抛 circular 错误。审查员对根因的静态分析正确。 - ❌ 端到端反驳:
script返回9007199254740993n+ 循环引用对象的真实 sandbox workflow 在本 PR 分支上——阻塞路径正常 completed(工具返回成功、workflow.json 落盘 completed),后台路径workflow-result投递消息照常到达。"已完成 workflow 被报为失败"/"后台投递丢失"两个用户可见影响均未发生。
原因:sandbox 子进程在 IPC 边界前已将结果归一化(sandbox-child.cjs:238-248:bigint→"123n" 字符串、循环→"[circular]"),父侧再次 toSerializable(sandbox.ts:382),磁盘恢复走 JSON.parse。details.result 在现有所有生产路径上不可能携带活的 BigInt/cycle。
仍然建议修改(成本低、消除隐患):jsonBytes 依赖了一个没有任何代码强制执行的隐藏前置条件"details 是 JSON-safe 的",未来任何绕过 sandbox 序列化的生产者都会重新引爆 P1 描述的崩溃链。请改用仓库既有 safeStringify/toSerializable 或仅测量有界字段,并补 BigInt/cycle 单元守卫测试——但这是防御性加固,不是用户可触发的 Must-Fix。
3. P2(dashboard 丢失刚完成的 run):实测成立
对抗测试复现:foreground run 完成后,损坏其 workflow.json(模拟持久化暂不可用),dashboard.ts 的 loadRunEntries 对非活跃 run if (!details) continue 直接跳过——run 从 dashboard 数据源消失;而本 PR 将 dashboardDetails() 改为仅 activeDetails(),retention 中保留(或可构造)的内存投影不参与兜底。实测向 loadRunEntries 合并该投影即可恢复显示。这与 issue #178 "operator 能看到 omitted/evicted,而不是把缺失误报为不存在"的要求相悖。请合并 retained projections 作为 fallback,并补 persistence-failure 的 dashboard 测试。
4. 值得肯定
有界投影设计、canonical artifacts 保护测试(persistWorkflowDeliveryState 不会覆盖 result.json)、session 级统计与 evicted 可观测性、UTF-8 安全截断、非法限额 fail-fast、replacement 失败不重复计数——方向与 issue #178 对齐,实现质量整体不错。补上复现测试与 P2 兜底后应可合入。
建议的拆分方案(逐层裁决)本 PR 约 85% 的新增行是纯增量代码,只有 第 1 层(可立即 approve):retention 模块本体
投影构建器 + 有界存储,自包含、有单元测试。此层合入时还没有任何生产代码消费它,行为零风险。合入前请顺手修一处: 第 2 层(可立即 approve):delivery receipt 帮助函数
外科手术式只更新 delivery 状态、不重写整个 第 3 层(需返工):index.ts 接线唯一包含行为变更、也是 P2 唯一所在地的部分。内部实为 4 件可再拆的事:
合并顺序第 3 层同时请补 issue #178 要求的扩展层级压力/回归测试(连续完成大量含 agents/logs 的 runs,断言内存有界、operator 可见 evicted 数量),以及能在 main 上失败的复现测试。 第 1、2 层拆出后我会立即 approve;第 3 层按上述要求修完即可快速 re-review。 |
|
已根据审查意见完成修复、补齐测试,并同步最新 P1:BigInt / 循环引用的 byte accounting
因此:
新增测试覆盖:
P2:canonical
|
问题
settled workflow details 原先没有明确的内存数量和聚合 UTF-8 字节上限。驱逐和重启行为还可能影响磁盘 artifacts 以及显式 run lookup。
改动
0作为不保留内存 projection。settledRunsEvicted及当前会话统计范围。验证
bun run lint通过。bun run typecheck通过,仅有既有 Effect 警告。--permission失败。Related to workflows: settled run details 缺少独立 retention bound #178