Files
ycode/docs/assessment-chat-projection-2026-10-15.md

136 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 同会话对话区差距评估(2026-10-15)
当前导入让两端拥有相同的用户问题、助手正文和大部分工具结果,但没有复制原版的完整显示投影。整页差距包含已证实的取消状态误判、工具名规范化缺失和内容块映射缺失,不能继续只靠 CSS token 调整来消除。
本次是只读评估,未修改生产代码、会话数据或原版。所有原版实现依据均来自已保存的 REA exports;实时截图由主上下文通过 REA 采集。本报告不粘贴原始思考文本、工具输出和图片内容。
## 样本与证据
- 原版:WorkBuddy 5.8.2。原会话 `4653e36f-6b2a-446f-a9c9-3f2d2d04644e`,YCode 副本 `6c000be8-b0e8-4768-9a7f-1a0d94a35951`,标题「开始新会话」。
- 历史导出:`.tmp/rea-workbuddy-session-with-images.json`,Evidence `ev_3c4593ae51bbee833ca9fcbe3b9ad172d108cc82cfd6783d9c06a1a78794f209`,JSONL SHA-256 `5311865227e9c278798b458d722cc54ac362aeb78f4eb52cece394d3608a04ed`。
- 原版脚本:`.tmp/rea-runtime-scripts.json`,Evidence `ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb`。
- 当前真实画面:`.tmp/rea-assessment-initial/workbuddy.png` / `layout.json`,Evidence `ev_d6e6920ff4e47f73a182fac5312c5f02393366a035445d18c8a6733a8c8a11ed`,2026-10-15T15:47:25.821Z,视口 1336 × 901。主上下文对照 YCode `.tmp/assessment-ycode/panel-closed.png` / `panel-open.png`。
- 本地导入产物:`.tmp/workbuddy-copy-session.json`、`.tmp/workbuddy-copy-report.json`、`.tmp/ycode-workbuddy-copy-ui-report.json`。
原版截图与 DOM 是先后观察,非原子快照;仅证明该会话当前可见范围。不能由最后一轮推断每个历史失败轮或所有展开状态均已验收。
## 导入目前真实保留了什么
| 项目 | 原可见分支中的记录 | YCode 副本 |
|---|---:|---:|
| 用户轮次 | 31 个可见用户问题,另 10 个注入通知被隐藏 | 31 |
| 助手文本记录 | 257 | 合并为 31 条助手消息中的 257 个 text part |
| 工具调用 / 结果 | 691 / 688 | 691 个工具,3 个无终态结果改为 cancelled |
| reasoning | 358 | 1 个 reasoning part |
| 图片 | 4 | 4 |
| 助手终态 | 249 completed、8 incomplete 文本记录 | 24 done、7 error 消息 |
| 富内容 part | 来源还有工具 renderer 与 metadata | 只有 text 257、tool 691、reasoning 1;无 artifact / plan / task / image part |
2 次 resend-fork-notice 共排除 357 条旧分支记录;31 个用户文本已剥离 prompt context。没有未匹配的工具结果。这些保证的是导入完整性与当前分支选择,不等同于显示结构或交互一致。
## 已证实的优先差距
### 1. 用户取消被导成红色错误,且取消提示显示两次
`src/shared/workbuddy-import.ts:168` 的 `finishAssistant` 优先判断 `lastAssistantError`,只要存在错误文案便将整轮设为 `error`。`src/shared/workbuddy-import.ts:239` 同时把所有 assistant output_text 原样保留为正文。
第 3、5、8、9、23、31 轮均满足:源末记录 `status: incomplete`,`providerData.error.message` 为 `Interrupted by user`,末正文也为 `Interrupted by user`。导入后两者都保留,形成英文正文和红色错误的重复展示。第 28 轮是 429,不能和用户取消混同处理。
原版 `workbuddy-provider-DkH2YFYM.js` SHA-256 `b588e875c469978f216beec86bdf4b6c33a31c0266f9bf996881b8dbf37b5dc7`,AST 方法锚点:
- `isHistoryInterruptedByUserChunk` offset 478633:识别精确文本 `Interrupted by user` 或 `[User Cancelled]`。
- `projectHistoryAssistantTextMessage` offset 475180:命中后设 `complete: true` 与 `buildCancelledMessageExtra`,不把该标记追加为普通正文。
第 31 轮已经通过主上下文 REA 画面闭环:原版显示「已取消 17m15s」和「用户已取消」,历史过程闭合;YCode 同一轮展开历史正文并在底部显示重复英文取消和红色 error。其他 5 个取消轮的具体画面仍须逐轮复核,但导入语义错误已有源码和数据证据。
修复应保留真实 429 错误,并把可明确识别的取消标记转换为显示终态;不能把所有 error 都粗暴转成 cancelled。
### 2. 错误终态未进入完成投影,直接拉长页面
`src/renderer/src/components/MessageBubble.tsx:124` 仅在 `done` 或 `cancelled` 时传 `turnFinished: true`。上述 7 个 error 因此被投影为仍未完成;摘要组的 `isRunning` 也成为 true。原版现代 `computeTurnFinished`(`src-DbE1_mgM.js` offset 975305)依据最后分组、request terminal、会话 busy 等信号计算结束,并不等同于这个两个状态的枚举判断。
对当前 `completed-fold.ts` 做内存 bundle 后直接调用纯模型,未改会话数据,结果如下。右列是把相同 parts 按终态投影的诊断结果,不能冒充每一轮原版截图。
| 轮次 | 当前状态 | 当前根渲染单元 | 按终态投影的根正文锚点 | 当前完成 / 过程折叠 | 终态诊断折叠 |
|---|---|---:|---:|---:|---:|
| 3 | error | 11 | 2 | 0 | 2 |
| 5 | error | 17 | 2 | 0 | 2 |
| 8 | error | 13 | 2 | 0 | 2 |
| 9 | error | 3 | 2 | 0 | 2 |
| 23 | error | 3(模型为 null,原 parts 直接渲染) | 2 | 0 | 2 |
| 28 | error / 429 | 13 | 2 | 0 | 2 |
| 31 | error / 用户取消 | 21 | 2 | 0 | 2 |
第 31 轮原版已确认闭合,其差距首先是状态与消息投影。取消语义修复会自然修复这 6 轮的主折叠门控;真实 error 轮还需明确原版终态契约。
### 3. 原版 provider 做了工具规范化,副本直接使用原始工具名
原版 provider 的 `Bi` alias 表 offset 190005、`canonicalizeToolName` offset 191155,以及 `normalizeWorkbuddyNotification` offset 290986,会在 UI 前规范化工具名和字段;`unwrapDeferExecuteTool` offset 287955 将延迟调用展开为目标工具并改用 `params`。
YCode 导入 `src/shared/workbuddy-import.ts:261` 直接保存 `record.name`。`ToolCallRenderer.tsx:102` 的有限 alias 表不能替代 provider 全流程;`MessageBubble.tsx:65` 的分类又另有一份不完整名单。
| 本会话原工具名 | 次数 | 原版规范化或专门路径 | 当前 YCode |
|---|---:|---|---|
| TaskCreate / TaskUpdate | 10 / 14 | `todo_write`,provider 还调用 `todoManager.ensureNormalized` | 无 alias,走通用卡片 |
| DeferExecuteTool | 12 | 解包目标 `mcp__rea__*` 工具及 `params` | 通用 DeferExecuteTool 卡片 |
| present_files | 10 | 存在专门 compact view 与产物来源识别 | 通用卡片,未生成 artifact part |
| AskUserQuestion | 1 | `askuserquestion`,inline question 分类、回答恢复 | 大写名称未命中 question renderer,也未命中 MessageBubble inline 分类 |
这 47 / 691 次调用确定进入现有通用兜底。另 644 次虽然命中某个已实现 renderer,并不代表已完成内容、展开默认值、预览和像素验收。
`present_files` 的 10 个调用含 21 条文件引用(可能重复),副本没有 artifact part;原版当前画面有「13 产物」入口。文件引用不是 13 个独立产物的等价计数,必须恢复原版产物提取、过滤、去重、归属与入口,而非直接将数字设为 13。
### 4. 正文 spacing 还没有消费原版的排列结论
原版 `src-DbE1_mgM.js` SHA-256 `6c6ce63c93854783270e855572797d75e536e3b8d4548410e31fe9d147e1feb4`,`markBodyTextSpacing` offset 946304,按最后正文、前一个非空块是否工具、回合是否结束,分别输出 `both` / `top` / `bottom` spacing。
YCode `MessageBubble.tsx:172` 仍只按 `index > 0` 添加 `cr-text-block--spaced-top`,其适配 CSS 只有 `margin-top: 12px`(`source-adapters.css:15`)。`CompletedFold` 已返回 render context,但这里没有使用它恢复原版 spacing。即使相同文本和字体,混排正文与工具、折叠前后相邻关系仍会产生系统性间距差异。具体像素影响需在相同展开状态截图上测量。
## 已知信息损失及验证边界
### reasoning:有源字节,但还不能凭 JSONL 直接认定全部应显示
可见分支中 357 个 reasoning 的 `content: []`,但 `rawContent` 是 `[{ type: 'reasoning_text', text: ... }]` 形状,另 1 个有显式 content。导入器 `workbuddy-import.ts:254` 明确排除 rawContent,所以当前只保留 1 个 reasoning。
已经证明数据在导出中存在,不是无法取得源码或缺少字节。仍未证明原版历史回放会把这 357 个 raw reasoning 全部投影为可见思考块:已保存 renderer/provider 脚本不含 JSONL 的 reasoning_text 处理入口,该环节可能在 daemon/replay producer。必须通过 REA 查回放转换或选定展开状态观察后,按原版显示契约转换,不能仅因存在 text 就展示全部 raw reasoning。
若需要显示,缺失 reasoning 会改变连续 foldable 段、工具摘要中的消息数及展开内容;只恢复字体无助于此。
### 模型信息、消息身份与合并
原可见 assistant 记录含 requestModelId/requestModelName/model;222 条来自 deepseek-v4.1-flash,28 条来自 glm-5.3-flash,7 条取消/失败末记录没有模型字段。副本 assistant 只保留 id、role、content、createdAt、status、parts、tools、turnDurationMs,缺少模型显示、request 身份和原消息边界。
导入将每个可见用户问题后的全部助手记录合为一条;原版 provider 按 messageId/requestId 累积再交给上层分组。`projectHistoryAssistantTextMessage` 对同一 message 的相邻同类型 text/reasoning 会直接连接;YCode 每条 assistant source record 单独成为 text part,content 再用两个换行连接。
当前样本存在 257 个文本记录、约 250 个非空 provider messageId。合为 31 条并不必然错误(原版也有 turn grouping),但不能仅用 31/31 消息数证明分组等价。须比较按 turn 的有序「显示块树」,包括同类型连续连接、去重、正文锚点、source ID 到显示节点的映射。恢复模型显示可以保留纯展示 metadata,无需接入原服务端模型。
### 工具结果与 metadata
当前 688 个结果的 renderer 类型:text 336、list 1、code 101、diff 188、todo 24、无 renderer 38。导入保留 title/content/renderer/rawResponse/error/acpV2PlanSnapshot,并把 rawResponse 放入当前专用视图会读取的 namespace,不能笼统声称 rawResponse 全丢了。
丢弃字段中有 10 个 terminalId 和 12 个 mcpMeta。历史副本不应恢复可执行原 terminal/session,但可以根据原版显示需要保留经白名单转换的静态展示字段。需要区分「为了避免恢复执行态而不导入 native ID」与「因此连静态显示内容也缺失」。todo renderer 的 24 份计划/任务快照已有字节,主要先解决规范化和对应 view 接入。
### 耗时
当前 turnDurationMs 取该用户 timestamp 到本轮已接收的最后助手/工具结果 timestamp;原版 `computeTurnDurationMs`(`src-0FGg1seX.js` offset 757590)取分组内用户 createTime 与 assistantEndTime,并跨连续助手组查找。现代 renderer 也消费 extra.turnDurationMs/assistantEndTime/processingStartedAt。
第 31 轮导入值 1,035,822 ms 格式化为 17m15s,恰与当前原版截图相同,因此这一轮耗时不构成已证实差异。其他轮、跨请求或后台工具结束晚于助手的情况仍应逐轮比较,不能直接换一个估算公式就宣称修复。
## 长任务应先处理的顺序与验收
1. 建立本会话按 source record/provenance 回溯的显示块树基线,分清取消、真实失败与正常完成;先修 6 个明确取消轮及最后一轮闭合效果。
2. 恢复 provider 展示规范化层:alias、defer 解包、question 回答/分类、todo snapshot 与 present_files 产物归属;执行层继续使用自己的实现。
3. 完成原版 spacing、模型显示 metadata、附件/产物入口和历史工具默认展开状态,再做 CSS/图标/尺寸修正。
4. 对同一会话至少覆盖首轮、带图片轮、工具密集轮、提问轮、todo 轮、取消轮、429 轮、最后一轮;每个点记录原版 REA Evidence、原窗口尺寸、主题、左右面板状态、滚动锚点和每层折叠状态。
5. 验收先比较显示块树与可见文本/状态,再比布局矩形、字体、截图像素及操作结果。整页差异不能用少数通用 fixture 通过代替。
阻碍目前主要是数据到 UI 的转换契约和真实状态覆盖,已有脚本、历史字节和 REA 画面足以开始修复。reasoning 的历史显示契约及部分原版回放 metadata 是明确未知项,需要 REA 补证;不需要为上述已证实问题先接入云端服务或子代理调度。
## 本次验证与修改范围
- 只读统计 REA JSONL,按已存在 resend-fork-notice 规则选择当前分支,再和副本数据计数比较。
- 使用 `@babel/parser` / `@babel/traverse` 只解析 REA 保存的脚本文本,记录上述 AST 方法与字符 offset、脚本 SHA。
- 使用 esbuild `write: false` 将本地 completed-fold.ts 内存打包,直接调用纯模型复现 7 个 error 轮的门控差异;没有修改生产代码或生成替代会话。
- 主上下文提供最后一轮原版 REA 与 YCode 真实画面对照。没有自行重复 live 采集。
- 本子任务唯一新增文件:本报告。未运行构建或回归,因为无实现变更;纯模型诊断及数据审计均成功。AST 首次遍历遇到无名称 class method,补充空值判断后完成,只读操作未留下文件改动。