feat: Session/Memory 多后端回放一致性测试框架 (issue #89)#178
Conversation
- replay harness: 同一组轨迹驱动 InMemory/SQLite/Redis,比较事件/state/memory/summary - 归一化(占位符,保留字段存在性)+ JSONPath 精确 allowed_diff + 覆盖率治理 - summary: SDK 确定性模型 + 三分比较 + loss/overwrite/affiliation 检测 - 检出验证: 快照层注入 + 端到端后端注入(改 SQL 行 / Redis key 重读) - 实测发现 SQLite summary 持久化 drift,标 KNOWN_DRIFT 只报告不改 - 29 tests pass, 1 skipped (Redis 需 TRPC_REPLAY_REDIS_URL)
|
I have read the CLA Document and I hereby sign the CLA |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #178 +/- ##
==========================================
Coverage ? 87.86456%
==========================================
Files ? 482
Lines ? 45157
Branches ? 0
==========================================
Hits ? 39677
Misses ? 5480
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
在replay目录下增加一下REDAME.md文档,说明一下测试需要注意的地方, |
回应维护者 raychen911 的 review(CHANGES_REQUESTED): 1. design.md 新增 §6.1「正/负向双向验证」:集中说明同一组 10 case 既测正向(不注入→100% match, FPR=0)又测负向(注入→100% 检出), 指向 test_replay_injections.py(快照层 8 种 kind + 端到端 SQL/Redis)。 2. plan + design 从 docs/superpowers/ 移入 tests/sessions/replay/, 修正内部 SDK 源码相对链接(../../ → ../../../)。 3. session_memory_summary_diff_report.json 从仓库根移至 tests/sessions/, 同步改 REPORT_PATH 与 report.py 注释,避免断链。 4. 新增 tests/sessions/replay/README.md(测试注意事项 7 条)。 验证: replay 测试 30 passed/1 skipped、yapf/flake8 全绿、全局引用无断链。
|
回应维护者 raychen911 的 review(CHANGES_REQUESTED):
验证: replay 测试 30 passed/1 skipped、yapf/flake8 全绿、全局引用无断链。 |
- tests/sessions/replay/2026-07-13-session-memory-replay-consistency.md → IMPLEMENTATION_PLAN.md - 同步更新 design.md 目录树与 README.md 引用
AI Code Review基于我对 diff 和 SDK 上下文的深入分析,以下是我的审查结果。 发现的问题🚨 Critical
|
- Critical: inject_sql_diff(state_value) 改为 Python 层处理避免双重序列化(helloopenworld) - inject_redis_diff: 设置 decode_responses=True + 资源清理(client.close()) - redis_backend: 统一 is_async=True 与 SDK 推荐一致 - harness: 添加 case 涉 memory 操作时 memory 非空断言(避免注入漏检) - report: known_drift_cases 纳入 DiffReport schema(schema 一致性) - summary_checks: 删除 SUMMARY_SIM_THRESHOLD 死代码(避免误导) - 测试补充: 新增 SQL/Redis state_value 端到端测试 验证: replay 测试 4 passed/2 skipped(Redis opt-in),无回归。
helloopenworld review 建议删除未用常量/函数,但 summary_text_similarity 实际被 test_replay_unit.py 单测覆盖(line 218-220),误删导致 CI test step4 ImportError。 现恢复 summary_text_similarity + _tokenize(保留单测),仅删除真正无调用方的 SUMMARY_SIM_THRESHOLD 常量。本地 replay 测试 31 passed/2 skipped。
AI Code Review已确认行号。正在撰写审查报告。 发现的问题🚨 Critical无。
|
Warning: build_diff_report 的 FPR 此前把 known_drift 计入分子分母,与设计 §6 「仅按正常 case 计算」矛盾(10 case 会算出 0.2 而非 0.0,E2E 靠手动覆盖修正, 单测因只构造无 drift case 而掩盖)。现加 known_drift_cases 参数(向后兼容), 内部排除 drift 计算 FPR;E2E 改为传参并去掉覆盖式修补。 Suggestion: - injectors.py: UPDATE OR REPLACE → UPDATE(避免主键先删后插重置非主键列) - test_replay_injections.py: CASES_DIR 改基于 __file__(与 consistency 一致,消除硬编码) 测试: 补 test_report_fpr_excludes_known_drift mixture 单测(1 drift + 1 正常 mismatch + 1 正常 match),锁定 FPR=0.5 排除 drift 契约。 验证: replay 测试 32 passed/2 skipped、yapf/flake8 全绿。
AI Code Review好的,两个内存后端匹配方式相同。报告确认 我现在已经深入了解了。让我识别一下实际值得报告的问题。让我重新考虑一下 让我检查一下 现在让我更仔细地重新考虑一下 现在, 现在让我验证 现在让我重新考虑我标记的那个潜在 真正的 Bug:在 现在让我考虑 现在让我确定真正有影响的问题。让我重新检查 现在是一个真正值得关注的点:harness 但这是一个真正的问题:harness 构建了 现在让我检查一下 现在我有信心了。让我把真正的发现写下来。让我重新考虑一下是否存在任何 Critical(关键)问题。 让我重新检查一件事 —— 现在,一个真正的问题: 让我验证 InMemory 后端 没有被复用服务中的 TTL 问题。 现在让我考虑 让我检查最后一个潜在的实际 Bug:在 查看 等等,这是 Redis 测试,默认会被跳过(没有 SQL 版本( 但是 Redis 版本只使用了 让我确认一下 Redis 的 state 测试确实没有填充状态。 查看 2882-2884 行: 这是一个真正的 Bug —— Redis 的 现在让我再重新考虑一下 SQL 的 让我再验证一下 Redis 的 所以只有 Redis 的状态测试坏了。让我再检查一下:Redis 现在让我再重新考虑一下 SQL 现在让我确定发现的问题。让我检查一下 让我检查一下比较器中 现在, 现在让我检查一个潜在的 实际问题: 让我验证测试框架中的 好的,我已经充分覆盖了。让我再快速验证一下 现在让我再重新考虑一下 E2E 测试中 现在让我重新考虑一下已提交的报告工件是否是 测试期间重新生成 的。 实际上, 让我最终确定。我发现的真正问题是:
让我再重新考虑一下 SQL 状态测试中是否有任何问题: 等等 —— 实际上在 SQL 现在让我再验证一下 让我再重新考虑一下是否存在 资源泄漏: 现在让我重新考虑一下 让我验证一下: 现在让我完成最终结论。主要问题:
让我重新考虑 #1 的严重性 —— 它在跳过的测试中,因此不会阻塞 CI。但根据指令,跳过/可选的测试仍然要按实际执行风险进行评估;如果 Redis 可达,它就会运行并失败。这是一个警告(测试有效性)。我会将其标记为警告。 让我最后再重新考虑一下 harness 的 现在让我再次检查 让我再重新考虑一下 让我验证一下没有 安全性 问题:注入器使用参数化查询(没有 SQL 注入)。Redis URL 来自环境变量。没有凭据泄漏。报告包含会话内容(文本) —— 不是敏感信息。没问题。 现在让我重新考虑一下已提交的 让我最终完成。为了全面起见,让我再重新考虑一下 E2E 测试的 实际上让我重新考虑一下 —— E2E 创建了 2 个后端(in_memory,sqlite :memory:)并运行了 10 个用例。SQLite :memory: 很快。20秒应该足够了。在负载下 30秒可能会很紧张。但这是一个真正的超时风险。我会提到它。 让我写下审查意见。 实际上,让我重新考虑一下 Redis 状态测试是真的是坏的,还是我误读了。让我重读 2880-2902 行。 2880-2883 行: 2884 行: 2886-2891 行: 所以 这是一个真正的 Bug。警告。 让我再检查一下相同的 Redis 测试是否至少通过 现在让我写下结论。我也重新考虑一下 让我最后确定 Suggestion 的数量限制(最多 2 条):
两个都还可以。实际上 #2 在文档字符串中已有说明并预留;价值较低。我还是只保留 #1 作为建议吧,再加一条关于 E2E 超时不稳定性的内容。嗯。让我挑出 2 条最有价值的。 实际上,关于 E2E 30秒超时导致不稳定性的担忧是比
让我重新考虑一下 E2E 超时是否真的有风险。测试执行 10 个用例 × 2 个后端 = 20 次 让我最终确定为:1 个警告(Redis 状态测试),1 条建议( 让我按照要求的格式写出来。基于我对 发现的问题
|
概述
实现一个可复用的回放一致性(replay consistency)框架:用同一组标准化 Agent 轨迹驱动 InMemory / SQLite / Redis 三个后端,经规范化比较事件、state、memory 与 Session Summary,自动生成可定位到
session_id / event_index / summary_id / field_path的差异报告。它既是测试工具,也是后端实现质量的基准。Closes #89
主要改动
replay harness(
tests/sessions/replay/)harness.py:ReplayCase/ReplayOp/ReplayBackend/ReplaySnapshot数据模型 +replay_case()驱动 +_DeterministicSummarizer(覆写_compress_session_to_summary,跑 SDK 真实压缩流程、不调 LLM)normalizer.py:占位符归一化(保留字段存在性)、剥离temp:state、memory 确定性排序comparator.py:单一递归visit(),DiffEntry 内联定位字段allowed_diff.py:JSONPath 精确匹配(token 化,避开 fnmatch 字符集陷阱)+ 强制 reason + 覆盖率治理(条数 ≤ 8、占比 ≤ 10%)summary_checks.py:loss / overwrite / affiliation 三类专项 + 分词 Jaccard 语义相似度injectors.py:快照层注入 + 端到端后端注入report.py/backends.py:schema_version=3 报告 / 三后端实例化 + env 门控replay case(
replay_cases/cases.jsonl):10 条,覆盖 issue 全部 8 类场景(单轮/多轮/工具调用/state 覆写/memory 读写/summary 生成与更新/summary 截断/异常恢复)报告产物:
session_memory_summary_diff_report.json(schema_version=3)设计文档:
docs/superpowers/specs/2026-07-13-session-memory-replay-consistency-design.md后端与运行模式
:memory:)TRPC_REPLAY_SQL_URLTRPC_REPLAY_REDIS_URL,未设置则pytest.skip三后端显式传同一
SessionServiceConfig(store_historical_events=True)消除默认值差异;memory 三后端enabled=True;不要求本地安装真实 Redis/MySQL。归一化与比较策略
temp:state;memory entry timestamp 归一化 + 排序;long_running_tool_ids的 None / 空集合统一。检出验证(两层)
UPDATE events SET author=.../ 改 Redis key,重新get_session读出,验证 harness 对真实后端数据漂移的感知能力。验收映射
test_each_case_detects_injection+ 8 类 kind + 端到端 SQL/Redissession_id/event_index/summary_id/field_path/双后端值本地验证