fix(transcript): mark dangling tool history incomplete - #7340
Conversation
|
Thanks for the PR! Template looks good ✓ Problem: observed bug from the #6999 audit — Direction: aligned. Correctly reporting completeness is fundamental to the SDK's transcript projection API. A consumer that trusts Size: not applicable — no core paths touched. 5 production lines (one Approach: the scope feels right. Uses the existing Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:来自 #6999 审计的已观测 bug—— 方向:对齐。正确报告完整性是 SDK transcript 投影 API 的基础能力。信任 规模:不适用——未触及核心路径。5 行生产代码(一个 方案:范围合理。使用现有 进入代码审查 🔍 — Qwen Code · qwen3.7-max Reviewed at |
Code ReviewIndependent proposal: given the problem (dangling tool calls get synthetic failed results but Comparison with the diff: the PR does exactly this. The The diagnostic flows through the established path: No critical blockers. No convention violations. TestingUnit tests (applied PR diff to worktree, ran both changed test files): Typecheck ( Tmux smoke test (non-TUI change — verified build and CLI startup): 中文说明代码审查独立方案: 针对该问题(悬空调用获得合成失败结果但 与 diff 对比: PR 完全这样做了。 diagnostic 通过既有路径流转: 无关键阻塞项。无约定违反。 测试单元测试(将 PR diff 应用到 worktree,运行两个变更的测试文件):全部通过(6 + 14 = 20 个测试)。 类型检查(acp-bridge 的 Tmux 冒烟测试(非 TUI 变更——验证构建和 CLI 启动):CLI 正常启动和退出。 — Qwen Code · qwen3.7-max Reviewed at |
|
Confidence: 5/5 Clean, focused correctness fix. One LGTM, approving. ✅ 中文说明置信度:5/5 干净、聚焦的正确性修复。 LGTM,批准。✅ — Qwen Code · qwen3.7-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
— qwen3.7-max via Qwen Code /review
ytahdn
left a comment
There was a problem hiding this comment.
Reviewed. Changes look good — minimal fix for dangling tool call completeness diagnostic, with regression tests at both ACP and SDK layers.
|
Released in v0.20.1. |
What this PR does
This follow-up makes incomplete offline ChatRecord history explicit when a persisted tool call has no matching result.
Why it's needed
The audit after #6999 found that replay already synthesizes a failed tool result for a dangling call, but the public projection still reports the transcript as complete and provides no diagnostic identifying the missing persisted result.
Why the other audit findings are out of scope
HistoryReplayerused the same top-level-only outcome predicate, so feat(webshell): replay ChatRecord history in readonly WebShell #6999 inherited rather than introduced this behavior in the shared replay machine. A fully persisted failed result is still a complete projection and needs no diagnostic; only the pre-existing tool-status mapping differs.parentUuidfragments: the transcript reader has unconditionally aggregated same-UUID segments since feat(serve): Add cursor-paged transcript replay endpoint #6525. feat(webshell): replay ChatRecord history in readonly WebShell #6999 added shared record preparation and a conflict diagnostic but retained that existing aggregation behavior.These findings are therefore not regressions introduced by the real #6999 ChatRecord projection path and are not required in this focused follow-up. They can be tracked separately if their existing behavior needs to change.
Reviewer Test Plan
How to verify
completeis false, and themissing_tool_resultdiagnostic identifies the source record.Evidence (Before & After)
Before: a dangling call rendered as failed while its transcript was still reported as complete. After: focused ACP and SDK regression suites cover the completeness diagnostic and public projection result. No TUI surface changes.
Tested on
Environment (optional)
Node.js workspace tests and builds without a sandbox.
Risk & Scope
complete: falseas a hard failure will now correctly reject dangling persisted history.Linked Issues
Follow-up to #6999.
中文说明
本 PR 做了什么
这个 follow-up 会在持久化工具调用缺少匹配结果时,明确标记离线 ChatRecord 历史不完整。
为什么需要
#6999 合并后的审计发现,回放虽然已经会为悬空调用生成失败工具结果,但公共投影仍将 transcript 报告为完整,也没有 diagnostic 指出缺失的持久化结果。
为什么其他审计项不在本 PR 范围内
HistoryReplayer已使用同样的、只读取顶层 outcome 的判断,因此 feat(webshell): replay ChatRecord history in readonly WebShell #6999 只是让共享 replay machine 继承了该行为,并未引入它。完整持久化的失败结果仍属于完整投影,不需要 diagnostic;差异仅在于原有的工具状态映射。parentUuid冲突 fragment:transcript reader 从 feat(serve): Add cursor-paged transcript replay endpoint #6525 起就会无条件聚合同 UUID segment。feat(webshell): replay ChatRecord history in readonly WebShell #6999 新增了共享 record preparation 和冲突 diagnostic,但保留了原有聚合行为。因此,这些发现都不是实际 #6999 ChatRecord 投影链路引入的回归,也不是本次聚焦 follow-up 的必要修复。如果需要改变这些既有行为,可以单独跟踪。
Reviewer 测试计划
如何验证
complete为 false,并且missing_tool_result诊断指向源记录。证据(修复前后)
修复前:悬空调用显示为失败,但 transcript 仍被报告为完整。修复后:聚焦的 ACP 和 SDK 回归测试覆盖完整性 diagnostic 与公共投影结果。没有 TUI 表面变化。
测试平台
环境(可选)
Node.js workspace 测试与构建,未启用 sandbox。
风险与范围
complete: false视为硬失败的消费者现在会正确拒绝悬空的持久化历史。关联 Issue
#6999 的 follow-up。